Implemented object details view
This commit is contained in:
parent
3b0f75e9bc
commit
8fee0bae58
|
@ -723,6 +723,8 @@ class SidebandApp(MDApp):
|
||||||
if len(modifiers) > 0 and modifiers[0] == 'ctrl' and (text == "w"):
|
if len(modifiers) > 0 and modifiers[0] == 'ctrl' and (text == "w"):
|
||||||
if self.root.ids.screen_manager.current == "conversations_screen":
|
if self.root.ids.screen_manager.current == "conversations_screen":
|
||||||
self.quit_action(self)
|
self.quit_action(self)
|
||||||
|
elif self.root.ids.screen_manager.current == "object_details_screen":
|
||||||
|
self.object_details_screen.close_action()
|
||||||
else:
|
else:
|
||||||
self.open_conversations(direction="right")
|
self.open_conversations(direction="right")
|
||||||
if len(modifiers) > 0 and modifiers[0] == 'ctrl' and (text == "s" or text == "d"):
|
if len(modifiers) > 0 and modifiers[0] == 'ctrl' and (text == "s" or text == "d"):
|
||||||
|
@ -759,6 +761,8 @@ class SidebandApp(MDApp):
|
||||||
self.close_sub_hardware_action()
|
self.close_sub_hardware_action()
|
||||||
elif self.root.ids.screen_manager.current == "hardware_serial_screen":
|
elif self.root.ids.screen_manager.current == "hardware_serial_screen":
|
||||||
self.close_sub_hardware_action()
|
self.close_sub_hardware_action()
|
||||||
|
if self.root.ids.screen_manager.current == "object_details_screen":
|
||||||
|
self.object_details_screen.close_action()
|
||||||
else:
|
else:
|
||||||
self.open_conversations(direction="right")
|
self.open_conversations(direction="right")
|
||||||
|
|
||||||
|
@ -847,14 +851,14 @@ class SidebandApp(MDApp):
|
||||||
Clock.schedule_once(cb, 0.15)
|
Clock.schedule_once(cb, 0.15)
|
||||||
Clock.schedule_once(cbu, 0.15+0.25)
|
Clock.schedule_once(cbu, 0.15+0.25)
|
||||||
|
|
||||||
def open_conversation(self, context_dest):
|
def open_conversation(self, context_dest, direction="left"):
|
||||||
self.outbound_mode_paper = False
|
self.outbound_mode_paper = False
|
||||||
if self.sideband.config["propagation_by_default"]:
|
if self.sideband.config["propagation_by_default"]:
|
||||||
self.outbound_mode_propagation = True
|
self.outbound_mode_propagation = True
|
||||||
else:
|
else:
|
||||||
self.outbound_mode_propagation = False
|
self.outbound_mode_propagation = False
|
||||||
|
|
||||||
self.root.ids.screen_manager.transition.direction = "left"
|
self.root.ids.screen_manager.transition.direction = direction
|
||||||
self.messages_view = Messages(self, context_dest)
|
self.messages_view = Messages(self, context_dest)
|
||||||
|
|
||||||
self.messages_view.ids.messages_scrollview.effect_cls = ScrollEffect
|
self.messages_view.ids.messages_scrollview.effect_cls = ScrollEffect
|
||||||
|
@ -952,6 +956,10 @@ class SidebandApp(MDApp):
|
||||||
context_dest = self.messages_view.ids.messages_scrollview.active_conversation
|
context_dest = self.messages_view.ids.messages_scrollview.active_conversation
|
||||||
self.map_show_peer_location(context_dest)
|
self.map_show_peer_location(context_dest)
|
||||||
|
|
||||||
|
def peer_show_telemetry_action(self, sender):
|
||||||
|
if self.root.ids.screen_manager.current == "messages_screen":
|
||||||
|
self.object_details_action(self.messages_view, from_conv=True)
|
||||||
|
|
||||||
def message_propagation_action(self, sender):
|
def message_propagation_action(self, sender):
|
||||||
if self.outbound_mode_paper:
|
if self.outbound_mode_paper:
|
||||||
self.outbound_mode_paper = False
|
self.outbound_mode_paper = False
|
||||||
|
@ -1248,10 +1256,7 @@ class SidebandApp(MDApp):
|
||||||
def lj():
|
def lj():
|
||||||
import webbrowser
|
import webbrowser
|
||||||
webbrowser.open("https://unsigned.io/donate")
|
webbrowser.open("https://unsigned.io/donate")
|
||||||
if not RNS.vendor.platformutils.is_android():
|
threading.Thread(target=lj, daemon=True).start()
|
||||||
threading.Thread(target=lj, daemon=True).start()
|
|
||||||
else:
|
|
||||||
lj()
|
|
||||||
|
|
||||||
self.information_screen.ids.information_scrollview.effect_cls = ScrollEffect
|
self.information_screen.ids.information_scrollview.effect_cls = ScrollEffect
|
||||||
self.information_screen.ids.information_logo.icon = self.sideband.asset_dir+"/rns_256.png"
|
self.information_screen.ids.information_logo.icon = self.sideband.asset_dir+"/rns_256.png"
|
||||||
|
@ -2935,6 +2940,17 @@ class SidebandApp(MDApp):
|
||||||
self.telemetry_screen.ids.telemetry_s_location.active = self.sideband.config["telemetry_s_location"]
|
self.telemetry_screen.ids.telemetry_s_location.active = self.sideband.config["telemetry_s_location"]
|
||||||
self.telemetry_screen.ids.telemetry_s_location.bind(active=self.telemetry_location_toggle)
|
self.telemetry_screen.ids.telemetry_s_location.bind(active=self.telemetry_location_toggle)
|
||||||
|
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_location.active = self.sideband.config["telemetry_s_fixed_location"]
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_location.bind(active=self.telemetry_location_toggle)
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_latlon.bind(focus=self.telemetry_save)
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_altitude.bind(focus=self.telemetry_save)
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_altitude.text = str(self.sideband.config["telemetry_s_fixed_altitude"])
|
||||||
|
try:
|
||||||
|
lat = self.sideband.config["telemetry_s_fixed_latlon"][0]; lon = self.sideband.config["telemetry_s_fixed_latlon"][1]
|
||||||
|
except:
|
||||||
|
lat = 0.0; lon = 0.0
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_latlon.text = f"{lat}, {lon}"
|
||||||
|
|
||||||
self.telemetry_screen.ids.telemetry_s_battery.active = self.sideband.config["telemetry_s_battery"]
|
self.telemetry_screen.ids.telemetry_s_battery.active = self.sideband.config["telemetry_s_battery"]
|
||||||
self.telemetry_screen.ids.telemetry_s_battery.bind(active=self.telemetry_save)
|
self.telemetry_screen.ids.telemetry_s_battery.bind(active=self.telemetry_save)
|
||||||
|
|
||||||
|
@ -2986,6 +3002,14 @@ class SidebandApp(MDApp):
|
||||||
self.sideband.stop_telemetry()
|
self.sideband.stop_telemetry()
|
||||||
|
|
||||||
def telemetry_location_toggle(self, sender=None, event=None):
|
def telemetry_location_toggle(self, sender=None, event=None):
|
||||||
|
if sender == self.telemetry_screen.ids.telemetry_s_location:
|
||||||
|
if self.telemetry_screen.ids.telemetry_s_location.active:
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_location.active = False
|
||||||
|
if sender == self.telemetry_screen.ids.telemetry_s_fixed_location:
|
||||||
|
if self.telemetry_screen.ids.telemetry_s_fixed_location.active:
|
||||||
|
self.telemetry_screen.ids.telemetry_s_location.active = False
|
||||||
|
|
||||||
|
|
||||||
if self.telemetry_screen.ids.telemetry_s_location.active:
|
if self.telemetry_screen.ids.telemetry_s_location.active:
|
||||||
if RNS.vendor.platformutils.is_android():
|
if RNS.vendor.platformutils.is_android():
|
||||||
if not check_permission("android.permission.ACCESS_COARSE_LOCATION") or not check_permission("android.permission.ACCESS_FINE_LOCATION"):
|
if not check_permission("android.permission.ACCESS_COARSE_LOCATION") or not check_permission("android.permission.ACCESS_FINE_LOCATION"):
|
||||||
|
@ -3012,6 +3036,7 @@ class SidebandApp(MDApp):
|
||||||
self.sideband.config["telemetry_send_appearance"] = self.telemetry_screen.ids.telemetry_send_appearance.active
|
self.sideband.config["telemetry_send_appearance"] = self.telemetry_screen.ids.telemetry_send_appearance.active
|
||||||
|
|
||||||
self.sideband.config["telemetry_s_location"] = self.telemetry_screen.ids.telemetry_s_location.active
|
self.sideband.config["telemetry_s_location"] = self.telemetry_screen.ids.telemetry_s_location.active
|
||||||
|
self.sideband.config["telemetry_s_fixed_location"] = self.telemetry_screen.ids.telemetry_s_fixed_location.active
|
||||||
self.sideband.config["telemetry_s_battery"] = self.telemetry_screen.ids.telemetry_s_battery.active
|
self.sideband.config["telemetry_s_battery"] = self.telemetry_screen.ids.telemetry_s_battery.active
|
||||||
self.sideband.config["telemetry_s_pressure"] = self.telemetry_screen.ids.telemetry_s_barometer.active
|
self.sideband.config["telemetry_s_pressure"] = self.telemetry_screen.ids.telemetry_s_barometer.active
|
||||||
self.sideband.config["telemetry_s_temperature"] = self.telemetry_screen.ids.telemetry_s_temperature.active
|
self.sideband.config["telemetry_s_temperature"] = self.telemetry_screen.ids.telemetry_s_temperature.active
|
||||||
|
@ -3022,6 +3047,28 @@ class SidebandApp(MDApp):
|
||||||
self.sideband.config["telemetry_s_angular_velocity"] = self.telemetry_screen.ids.telemetry_s_gyroscope.active
|
self.sideband.config["telemetry_s_angular_velocity"] = self.telemetry_screen.ids.telemetry_s_gyroscope.active
|
||||||
self.sideband.config["telemetry_s_acceleration"] = self.telemetry_screen.ids.telemetry_s_accelerometer.active
|
self.sideband.config["telemetry_s_acceleration"] = self.telemetry_screen.ids.telemetry_s_accelerometer.active
|
||||||
self.sideband.config["telemetry_s_proximity"] = self.telemetry_screen.ids.telemetry_s_proximity.active
|
self.sideband.config["telemetry_s_proximity"] = self.telemetry_screen.ids.telemetry_s_proximity.active
|
||||||
|
|
||||||
|
try:
|
||||||
|
alt = float(self.telemetry_screen.ids.telemetry_s_fixed_altitude.text.strip().replace(" ", ""))
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_altitude.text = str(alt)
|
||||||
|
self.sideband.config["telemetry_s_fixed_altitude"] = alt
|
||||||
|
except:
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_altitude.text = str(self.sideband.config["telemetry_s_fixed_altitude"])
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = self.telemetry_screen.ids.telemetry_s_fixed_latlon.text
|
||||||
|
l = s.strip().replace(" ","").split(",")
|
||||||
|
lat = float(l[0]); lon = float(l[1])
|
||||||
|
self.sideband.config["telemetry_s_fixed_latlon"] = [lat, lon]
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_latlon.text = f"{lat}, {lon}"
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
lat = self.sideband.config["telemetry_s_fixed_latlon"][0]
|
||||||
|
lon = self.sideband.config["telemetry_s_fixed_latlon"][1]
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_latlon.text = f"{lat}, {lon}"
|
||||||
|
except:
|
||||||
|
self.sideband.config["telemetry_s_fixed_latlon"] = [0.0, 0.0]
|
||||||
|
self.telemetry_screen.ids.telemetry_s_fixed_latlon.text = "0.0, 0.0"
|
||||||
|
|
||||||
self.sideband.save_configuration()
|
self.sideband.save_configuration()
|
||||||
self.sideband.setstate("app.flags.last_telemetry", time.time())
|
self.sideband.setstate("app.flags.last_telemetry", time.time())
|
||||||
|
@ -3205,22 +3252,24 @@ class SidebandApp(MDApp):
|
||||||
self.map_action()
|
self.map_action()
|
||||||
self.map_show(location)
|
self.map_show(location)
|
||||||
|
|
||||||
def map_display_telemetry(self, sender):
|
def map_display_telemetry(self, sender=None):
|
||||||
RNS.log("Display telemetry from "+str(sender), RNS.LOG_WARNING)
|
self.object_details_action(sender)
|
||||||
self.object_details_action()
|
|
||||||
|
|
||||||
def close_sub_map_action(self, sender=None):
|
def close_sub_map_action(self, sender=None):
|
||||||
self.map_action(direction="right")
|
self.map_action(direction="right")
|
||||||
|
|
||||||
def object_details_action(self, sender=None):
|
def object_details_action(self, sender=None, from_conv=False):
|
||||||
self.root.ids.screen_manager.transition.direction = "left"
|
self.root.ids.screen_manager.transition.direction = "left"
|
||||||
self.root.ids.nav_drawer.set_state("closed")
|
self.root.ids.nav_drawer.set_state("closed")
|
||||||
|
|
||||||
if self.object_details_screen == None:
|
|
||||||
self.object_details_screen = ObjectDetails(self)
|
|
||||||
|
|
||||||
self.root.ids.screen_manager.current = "object_details_screen"
|
if sender != None and hasattr(sender, "source_dest") and sender.source_dest != None:
|
||||||
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
|
if self.object_details_screen == None:
|
||||||
|
self.object_details_screen = ObjectDetails(self)
|
||||||
|
|
||||||
|
self.object_details_screen.set_source(sender.source_dest, from_conv=from_conv)
|
||||||
|
|
||||||
|
self.root.ids.screen_manager.current = "object_details_screen"
|
||||||
|
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
|
||||||
|
|
||||||
def map_create_marker(self, source, telemetry, appearance):
|
def map_create_marker(self, source, telemetry, appearance):
|
||||||
try:
|
try:
|
||||||
|
@ -3228,6 +3277,7 @@ class SidebandApp(MDApp):
|
||||||
a_icon = appearance[0]
|
a_icon = appearance[0]
|
||||||
a_fg = appearance[1]; a_bg = appearance[2]
|
a_fg = appearance[1]; a_bg = appearance[2]
|
||||||
marker = CustomMapMarker(lat=l["latitude"], lon=l["longtitude"], icon_bg=a_bg)
|
marker = CustomMapMarker(lat=l["latitude"], lon=l["longtitude"], icon_bg=a_bg)
|
||||||
|
marker.app = self
|
||||||
marker.source_dest = source
|
marker.source_dest = source
|
||||||
marker.location_time = l["last_update"]
|
marker.location_time = l["last_update"]
|
||||||
marker.icon = MDMapIconButton(
|
marker.icon = MDMapIconButton(
|
||||||
|
@ -3237,6 +3287,7 @@ class SidebandApp(MDApp):
|
||||||
on_release=self.map_display_telemetry,
|
on_release=self.map_display_telemetry,
|
||||||
)
|
)
|
||||||
marker.icon._default_icon_pad = dp(16)
|
marker.icon._default_icon_pad = dp(16)
|
||||||
|
marker.icon.source_dest = marker.source_dest
|
||||||
marker.add_widget(marker.icon)
|
marker.add_widget(marker.icon)
|
||||||
|
|
||||||
########
|
########
|
||||||
|
|
|
@ -472,6 +472,8 @@ class SidebandCore():
|
||||||
self.config["telemetry_bg"] = SidebandCore.DEFAULT_APPEARANCE[2]
|
self.config["telemetry_bg"] = SidebandCore.DEFAULT_APPEARANCE[2]
|
||||||
if not "telemetry_send_appearance" in self.config:
|
if not "telemetry_send_appearance" in self.config:
|
||||||
self.config["telemetry_send_appearance"] = False
|
self.config["telemetry_send_appearance"] = False
|
||||||
|
if not "telemetry_display_trusted_only" in self.config:
|
||||||
|
self.config["telemetry_display_trusted_only"] = False
|
||||||
|
|
||||||
if not "telemetry_s_location" in self.config:
|
if not "telemetry_s_location" in self.config:
|
||||||
self.config["telemetry_s_location"] = False
|
self.config["telemetry_s_location"] = False
|
||||||
|
@ -495,8 +497,12 @@ class SidebandCore():
|
||||||
self.config["telemetry_s_acceleration"] = False
|
self.config["telemetry_s_acceleration"] = False
|
||||||
if not "telemetry_s_proximity" in self.config:
|
if not "telemetry_s_proximity" in self.config:
|
||||||
self.config["telemetry_s_proximity"] = False
|
self.config["telemetry_s_proximity"] = False
|
||||||
if not "telemetry_display_trusted_only" in self.config:
|
if not "telemetry_s_fixed_location" in self.config:
|
||||||
self.config["telemetry_display_trusted_only"] = False
|
self.config["telemetry_s_fixed_location"] = False
|
||||||
|
if not "telemetry_s_fixed_latlon" in self.config:
|
||||||
|
self.config["telemetry_s_fixed_latlon"] = [0.0, 0.0]
|
||||||
|
if not "telemetry_s_fixed_altitude" in self.config:
|
||||||
|
self.config["telemetry_s_fixed_altitude"] = 0.0
|
||||||
|
|
||||||
if not "map_history_limit" in self.config:
|
if not "map_history_limit" in self.config:
|
||||||
self.config["map_history_limit"] = 7*24*60*60
|
self.config["map_history_limit"] = 7*24*60*60
|
||||||
|
@ -671,6 +677,8 @@ class SidebandCore():
|
||||||
return self._db_get_appearance(context_dest) or SidebandCore.DEFAULT_APPEARANCE
|
return self._db_get_appearance(context_dest) or SidebandCore.DEFAULT_APPEARANCE
|
||||||
|
|
||||||
def peer_display_name(self, context_dest):
|
def peer_display_name(self, context_dest):
|
||||||
|
if context_dest == self.lxmf_destination.hash:
|
||||||
|
return self.config["display_name"]
|
||||||
try:
|
try:
|
||||||
existing_conv = self._db_conversation(context_dest)
|
existing_conv = self._db_conversation(context_dest)
|
||||||
if existing_conv != None:
|
if existing_conv != None:
|
||||||
|
@ -753,10 +761,20 @@ class SidebandCore():
|
||||||
return self._db_telemetry(context_dest = context_dest, after = after, before = before, limit = limit) or []
|
return self._db_telemetry(context_dest = context_dest, after = after, before = before, limit = limit) or []
|
||||||
|
|
||||||
def peer_telemetry(self, context_dest, after = None, before = None, limit = None):
|
def peer_telemetry(self, context_dest, after = None, before = None, limit = None):
|
||||||
pts = self._db_telemetry(context_dest, after = after, before = before, limit = limit)
|
if context_dest == self.lxmf_destination.hash and limit == 1:
|
||||||
if pts != None:
|
try:
|
||||||
if context_dest in pts:
|
return [[self.latest_telemetry["time"]["utc"], self.latest_packed_telemetry]]
|
||||||
return pts[context_dest]
|
except:
|
||||||
|
RNS.log("An error occurred while retrieving telemetry from the database: "+str(e), RNS.LOG_ERROR)
|
||||||
|
return []
|
||||||
|
|
||||||
|
try:
|
||||||
|
pts = self._db_telemetry(context_dest, after = after, before = before, limit = limit)
|
||||||
|
if pts != None:
|
||||||
|
if context_dest in pts:
|
||||||
|
return pts[context_dest]
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("An error occurred while retrieving telemetry from the database: "+str(e), RNS.LOG_ERROR)
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -1142,8 +1160,10 @@ class SidebandCore():
|
||||||
dbc = db.cursor()
|
dbc = db.cursor()
|
||||||
|
|
||||||
# TODO: Implement limit
|
# TODO: Implement limit
|
||||||
|
limit_part = ""
|
||||||
order_part = " order by ts DESC"
|
if limit:
|
||||||
|
limit_part = " LIMIT "+str(int(limit))
|
||||||
|
order_part = " order by ts DESC"+limit_part
|
||||||
if context_dest == None:
|
if context_dest == None:
|
||||||
if after != None and before == None:
|
if after != None and before == None:
|
||||||
query = "select * from telemetry where ts>:after_ts"+order_part
|
query = "select * from telemetry where ts>:after_ts"+order_part
|
||||||
|
@ -1211,6 +1231,7 @@ class SidebandCore():
|
||||||
if "snr" in physical_link: remote_telemeter.sensors["physical_link"].snr = physical_link["snr"]
|
if "snr" in physical_link: remote_telemeter.sensors["physical_link"].snr = physical_link["snr"]
|
||||||
if "q" in physical_link: remote_telemeter.sensors["physical_link"].q = physical_link["q"]
|
if "q" in physical_link: remote_telemeter.sensors["physical_link"].q = physical_link["q"]
|
||||||
remote_telemeter.sensors["physical_link"].update_data()
|
remote_telemeter.sensors["physical_link"].update_data()
|
||||||
|
telemetry = remote_telemeter.packed()
|
||||||
|
|
||||||
query = "INSERT INTO telemetry (dest_context, ts, data) values (?, ?, ?)"
|
query = "INSERT INTO telemetry (dest_context, ts, data) values (?, ?, ?)"
|
||||||
data = (context_dest, telemetry_timestamp, telemetry)
|
data = (context_dest, telemetry_timestamp, telemetry)
|
||||||
|
@ -1245,22 +1266,26 @@ class SidebandCore():
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
def _db_get_appearance(self, context_dest):
|
def _db_get_appearance(self, context_dest):
|
||||||
conv = self._db_conversation(context_dest)
|
if context_dest == self.lxmf_destination.hash:
|
||||||
data_dict = conv["data"]
|
return [self.config["telemetry_icon"], self.config["telemetry_fg"], self.config["telemetry_bg"]]
|
||||||
try:
|
else:
|
||||||
if data_dict != None and "appearance" in data_dict:
|
conv = self._db_conversation(context_dest)
|
||||||
def htf(cbytes):
|
if conv != None and "data" in conv:
|
||||||
d = 1.0/255.0
|
data_dict = conv["data"]
|
||||||
r = round(struct.unpack("!B", bytes([cbytes[0]]))[0]*d, 4)
|
try:
|
||||||
g = round(struct.unpack("!B", bytes([cbytes[1]]))[0]*d, 4)
|
if data_dict != None and "appearance" in data_dict:
|
||||||
b = round(struct.unpack("!B", bytes([cbytes[2]]))[0]*d, 4)
|
def htf(cbytes):
|
||||||
return [r,g,b]
|
d = 1.0/255.0
|
||||||
|
r = round(struct.unpack("!B", bytes([cbytes[0]]))[0]*d, 4)
|
||||||
|
g = round(struct.unpack("!B", bytes([cbytes[1]]))[0]*d, 4)
|
||||||
|
b = round(struct.unpack("!B", bytes([cbytes[2]]))[0]*d, 4)
|
||||||
|
return [r,g,b]
|
||||||
|
|
||||||
appearance = [data_dict["appearance"][0], htf(data_dict["appearance"][1]), htf(data_dict["appearance"][2])]
|
appearance = [data_dict["appearance"][0], htf(data_dict["appearance"][1]), htf(data_dict["appearance"][2])]
|
||||||
|
|
||||||
return appearance
|
return appearance
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Could not retrieve appearance for "+RNS.prettyhexrep(context_dest)+": "+str(e), RNS.LOG_ERROR)
|
RNS.log("Could not retrieve appearance for "+RNS.prettyhexrep(context_dest)+": "+str(e), RNS.LOG_ERROR)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -1744,6 +1769,13 @@ class SidebandCore():
|
||||||
self.telemeter.enable(sensor)
|
self.telemeter.enable(sensor)
|
||||||
else:
|
else:
|
||||||
self.telemeter.disable(sensor)
|
self.telemeter.disable(sensor)
|
||||||
|
|
||||||
|
if self.config["telemetry_s_fixed_location"]:
|
||||||
|
self.telemeter.synthesize("location")
|
||||||
|
self.telemeter.sensors["location"].latitude = self.config["telemetry_s_fixed_latlon"][0]
|
||||||
|
self.telemeter.sensors["location"].longtitude = self.config["telemetry_s_fixed_latlon"][1]
|
||||||
|
self.telemeter.sensors["location"].altitude = self.config["telemetry_s_fixed_altitude"]
|
||||||
|
|
||||||
|
|
||||||
def get_telemetry(self):
|
def get_telemetry(self):
|
||||||
if self.config["telemetry_enabled"] == True:
|
if self.config["telemetry_enabled"] == True:
|
||||||
|
|
|
@ -868,6 +868,7 @@ MDScreen:
|
||||||
[
|
[
|
||||||
['arrow-down-bold-hexagon-outline', lambda x: root.app.telemetry_request_action(self)],
|
['arrow-down-bold-hexagon-outline', lambda x: root.app.telemetry_request_action(self)],
|
||||||
['upload-lock', lambda x: root.app.telemetry_send_update(self)],
|
['upload-lock', lambda x: root.app.telemetry_send_update(self)],
|
||||||
|
['wrench-cog', lambda x: root.app.close_any_action(self)],
|
||||||
['close', lambda x: root.app.close_any_action(self)],
|
['close', lambda x: root.app.close_any_action(self)],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1323,6 +1324,44 @@ MDScreen:
|
||||||
pos_hint: {"center_y": 0.3}
|
pos_hint: {"center_y": 0.3}
|
||||||
active: False
|
active: False
|
||||||
|
|
||||||
|
MDBoxLayout:
|
||||||
|
orientation: "horizontal"
|
||||||
|
size_hint_y: None
|
||||||
|
padding: [0,0,dp(24),dp(0)]
|
||||||
|
height: dp(48)
|
||||||
|
|
||||||
|
MDLabel:
|
||||||
|
text: "Fixed Location"
|
||||||
|
font_style: "H6"
|
||||||
|
|
||||||
|
MDSwitch:
|
||||||
|
id: telemetry_s_fixed_location
|
||||||
|
pos_hint: {"center_y": 0.3}
|
||||||
|
active: False
|
||||||
|
|
||||||
|
MDBoxLayout:
|
||||||
|
id: telemetry_fixed_location_fields
|
||||||
|
orientation: "horizontal"
|
||||||
|
size_hint_y: None
|
||||||
|
spacing: dp(16)
|
||||||
|
height: dp(64)
|
||||||
|
padding: [0, dp(0), 0, dp(0)]
|
||||||
|
# md_bg_color: [1,0,0,1]
|
||||||
|
|
||||||
|
MDTextField:
|
||||||
|
id: telemetry_s_fixed_latlon
|
||||||
|
size_hint: [0.618, None]
|
||||||
|
hint_text: "Latitude, longtitude"
|
||||||
|
text: ""
|
||||||
|
font_size: dp(24)
|
||||||
|
|
||||||
|
MDTextField:
|
||||||
|
id: telemetry_s_fixed_altitude
|
||||||
|
size_hint: [0.382, None]
|
||||||
|
hint_text: "Altitude"
|
||||||
|
text: ""
|
||||||
|
font_size: dp(24)
|
||||||
|
|
||||||
MDLabel:
|
MDLabel:
|
||||||
markup: True
|
markup: True
|
||||||
text: "\\n"
|
text: "\\n"
|
||||||
|
|
|
@ -41,6 +41,7 @@ class Messages():
|
||||||
def __init__(self, app, context_dest):
|
def __init__(self, app, context_dest):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.context_dest = context_dest
|
self.context_dest = context_dest
|
||||||
|
self.source_dest = context_dest
|
||||||
|
|
||||||
self.screen = self.app.root.ids.screen_manager.get_screen("messages_screen")
|
self.screen = self.app.root.ids.screen_manager.get_screen("messages_screen")
|
||||||
self.ids = self.screen.ids
|
self.ids = self.screen.ids
|
||||||
|
@ -302,9 +303,15 @@ class Messages():
|
||||||
def x():
|
def x():
|
||||||
try:
|
try:
|
||||||
telemeter = Telemeter.from_packed(packed_telemetry)
|
telemeter = Telemeter.from_packed(packed_telemetry)
|
||||||
tlm = telemeter.read_all()
|
|
||||||
if extra_telemetry and len(extra_telemetry) != 0:
|
if extra_telemetry and len(extra_telemetry) != 0:
|
||||||
tlm["physical_link"] = extra_telemetry
|
physical_link = extra_telemetry
|
||||||
|
telemeter.synthesize("physical_link")
|
||||||
|
if "rssi" in physical_link: telemeter.sensors["physical_link"].rssi = physical_link["rssi"]
|
||||||
|
if "snr" in physical_link: telemeter.sensors["physical_link"].snr = physical_link["snr"]
|
||||||
|
if "quality" in physical_link: telemeter.sensors["physical_link"].q = physical_link["quality"]
|
||||||
|
telemeter.sensors["physical_link"].update_data()
|
||||||
|
|
||||||
|
tlm = telemeter.read_all()
|
||||||
Clipboard.copy(str(tlm))
|
Clipboard.copy(str(tlm))
|
||||||
item.dmenu.dismiss()
|
item.dmenu.dismiss()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -598,6 +605,7 @@ MDScreen:
|
||||||
[['menu', lambda x: root.app.nav_drawer.set_state("open")],]
|
[['menu', lambda x: root.app.nav_drawer.set_state("open")],]
|
||||||
right_action_items:
|
right_action_items:
|
||||||
[
|
[
|
||||||
|
['map-marker-path', lambda x: root.app.peer_show_telemetry_action(self)],
|
||||||
['map-search', lambda x: root.app.peer_show_location_action(self)],
|
['map-search', lambda x: root.app.peer_show_location_action(self)],
|
||||||
['lan-connect', lambda x: root.app.message_propagation_action(self)],
|
['lan-connect', lambda x: root.app.message_propagation_action(self)],
|
||||||
['close', lambda x: root.app.close_settings_action(self)],
|
['close', lambda x: root.app.close_settings_action(self)],
|
||||||
|
|
|
@ -3,6 +3,17 @@ import RNS
|
||||||
|
|
||||||
from kivy.metrics import dp,sp
|
from kivy.metrics import dp,sp
|
||||||
from kivy.lang.builder import Builder
|
from kivy.lang.builder import Builder
|
||||||
|
from kivy.core.clipboard import Clipboard
|
||||||
|
from kivymd.uix.recycleview import MDRecycleView
|
||||||
|
from kivymd.uix.list import OneLineIconListItem
|
||||||
|
from kivy.properties import StringProperty, BooleanProperty
|
||||||
|
from kivy.effects.scroll import ScrollEffect
|
||||||
|
from sideband.sense import Telemeter
|
||||||
|
import threading
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
if RNS.vendor.platformutils.get_platform() == "android":
|
if RNS.vendor.platformutils.get_platform() == "android":
|
||||||
from ui.helpers import ts_format
|
from ui.helpers import ts_format
|
||||||
|
@ -14,13 +25,60 @@ class ObjectDetails():
|
||||||
self.app = app
|
self.app = app
|
||||||
self.widget = None
|
self.widget = None
|
||||||
self.object_hash = object_hash
|
self.object_hash = object_hash
|
||||||
|
self.coords = None
|
||||||
|
self.raw_telemetry = None
|
||||||
|
self.from_conv = False
|
||||||
|
|
||||||
if not self.app.root.ids.screen_manager.has_screen("object_details_screen"):
|
if not self.app.root.ids.screen_manager.has_screen("object_details_screen"):
|
||||||
self.screen = Builder.load_string(layou_object_details)
|
self.screen = Builder.load_string(layou_object_details)
|
||||||
self.screen.app = self.app
|
self.screen.app = self.app
|
||||||
|
self.screen.delegate = self
|
||||||
self.ids = self.screen.ids
|
self.ids = self.screen.ids
|
||||||
self.app.root.ids.screen_manager.add_widget(self.screen)
|
self.app.root.ids.screen_manager.add_widget(self.screen)
|
||||||
|
|
||||||
|
self.screen.ids.object_details_scrollview.effect_cls = ScrollEffect
|
||||||
|
self.telemetry_list = RVDetails()
|
||||||
|
self.telemetry_list.delegate = self
|
||||||
|
self.telemetry_list.app = self.app
|
||||||
|
self.screen.ids.object_details_scrollview.add_widget(self.telemetry_list)
|
||||||
|
|
||||||
|
def close_action(self, sender=None):
|
||||||
|
if self.from_conv:
|
||||||
|
self.app.open_conversation(self.object_hash, direction="right")
|
||||||
|
else:
|
||||||
|
self.app.close_sub_map_action()
|
||||||
|
|
||||||
|
def set_source(self, source_dest, from_conv=False):
|
||||||
|
self.object_hash = source_dest
|
||||||
|
|
||||||
|
if from_conv:
|
||||||
|
self.from_conv = True
|
||||||
|
else:
|
||||||
|
self.from_conv = False
|
||||||
|
|
||||||
|
self.coords = None
|
||||||
|
self.telemetry_list.data = []
|
||||||
|
appearance = self.app.sideband.peer_appearance(source_dest)
|
||||||
|
self.screen.ids.name_label.text = self.app.sideband.peer_display_name(source_dest)
|
||||||
|
self.screen.ids.coordinates_button.disabled = True
|
||||||
|
self.screen.ids.object_appearance.icon = appearance[0]
|
||||||
|
self.screen.ids.object_appearance.icon_color = appearance[1]
|
||||||
|
self.screen.ids.object_appearance.md_bg_color = appearance[2]
|
||||||
|
|
||||||
|
latest_telemetry = self.app.sideband.peer_telemetry(source_dest, limit=1)
|
||||||
|
if latest_telemetry != None and len(latest_telemetry) > 0:
|
||||||
|
telemeter = Telemeter.from_packed(latest_telemetry[0][1])
|
||||||
|
self.raw_telemetry = telemeter.read_all()
|
||||||
|
|
||||||
|
rendered_telemetry = telemeter.render()
|
||||||
|
if "location" in telemeter.sensors:
|
||||||
|
self.screen.ids.coordinates_button.disabled = False
|
||||||
|
self.telemetry_list.update_source(rendered_telemetry)
|
||||||
|
self.screen.ids.telemetry_button.disabled = False
|
||||||
|
else:
|
||||||
|
self.screen.ids.telemetry_button.disabled = True
|
||||||
|
self.telemetry_list.update_source(None)
|
||||||
|
|
||||||
def reload(self):
|
def reload(self):
|
||||||
self.clear_widget()
|
self.clear_widget()
|
||||||
self.update()
|
self.update()
|
||||||
|
@ -40,7 +98,131 @@ class ObjectDetails():
|
||||||
def get_widget(self):
|
def get_widget(self):
|
||||||
return self.widget
|
return self.widget
|
||||||
|
|
||||||
|
def copy_coordinates(self, sender=None):
|
||||||
|
Clipboard.copy(str(self.coords or "No data"))
|
||||||
|
|
||||||
|
def copy_telemetry(self, sender=None):
|
||||||
|
Clipboard.copy(str(self.raw_telemetry or "No data"))
|
||||||
|
|
||||||
|
class ODView(OneLineIconListItem):
|
||||||
|
icon = StringProperty()
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
class RVDetails(MDRecycleView):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.data = []
|
||||||
|
|
||||||
|
def update_source(self, rendered_telemetry=None):
|
||||||
|
if not rendered_telemetry:
|
||||||
|
rendered_telemetry = []
|
||||||
|
|
||||||
|
sort = {
|
||||||
|
"Physical Link": 10,
|
||||||
|
"Location": 20,
|
||||||
|
"Ambient Light": 30,
|
||||||
|
"Ambient Temperature": 40,
|
||||||
|
"Relative Humidity": 50,
|
||||||
|
"Ambient Pressure": 60,
|
||||||
|
"Battery": 70,
|
||||||
|
"Timestamp": 80,
|
||||||
|
}
|
||||||
|
self.entries = []
|
||||||
|
rendered_telemetry.sort(key=lambda s: sort[s["name"]] if s["name"] in sort else 1000)
|
||||||
|
for s in rendered_telemetry:
|
||||||
|
extra_entries = []
|
||||||
|
release_function = None
|
||||||
|
name = s["name"]
|
||||||
|
if name == "Timestamp":
|
||||||
|
ts = s["values"]["UTC"]
|
||||||
|
ts_str = datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
formatted_values = f"Recorded: [b]{RNS.prettytime(time.time()-ts, compact=True)} ago[/b] ({ts_str})"
|
||||||
|
elif name == "Battery":
|
||||||
|
p = s["values"]["percent"]
|
||||||
|
cs = s["values"]["_meta"]
|
||||||
|
formatted_values = f"{name}: [b]{p}%[/b] ({cs})"
|
||||||
|
elif name == "Ambient Pressure":
|
||||||
|
p = s["values"]["mbar"]
|
||||||
|
formatted_values = f"{name}: [b]{p} mbar[/b]"
|
||||||
|
elif name == "Ambient Temperature":
|
||||||
|
c = s["values"]["c"]
|
||||||
|
formatted_values = f"{name}: [b]{c}° C[/b]"
|
||||||
|
elif name == "Relative Humidity":
|
||||||
|
r = s["values"]["percent"]
|
||||||
|
formatted_values = f"{name}: [b]{r}%[/b]"
|
||||||
|
elif name == "Physical Link":
|
||||||
|
rssi = s["values"]["rssi"]
|
||||||
|
snr = s["values"]["snr"]
|
||||||
|
q = s["values"]["q"]
|
||||||
|
formatted_values = f"Link Quality: [b]{q}%[/b], RSSI: [b]{rssi} dBm[/b], SNR: [b]{snr} dB[/b]"
|
||||||
|
elif name == "Location":
|
||||||
|
lat = s["values"]["latitude"]
|
||||||
|
lon = s["values"]["longtitude"]
|
||||||
|
alt = s["values"]["altitude"]
|
||||||
|
speed = s["values"]["speed"]
|
||||||
|
bearing = s["values"]["bearing"]
|
||||||
|
accuracy = s["values"]["accuracy"]
|
||||||
|
updated = s["values"]["updated"]
|
||||||
|
updated_str = f", Logged: [b]{RNS.prettytime(time.time()-updated, compact=True)} ago[/b]"
|
||||||
|
if speed > 0.01:
|
||||||
|
speed_str = ", Speed: [b]{speed} Km/h[/b]"
|
||||||
|
else:
|
||||||
|
speed_str = ""
|
||||||
|
coords = f"{lat}, {lon}"
|
||||||
|
self.delegate.coords = coords
|
||||||
|
formatted_values = f"Coordinates: [b]{coords}[/b], Altitude: [b]{alt} meters[/b]"+speed_str+f", Bearing: [b]{bearing}°[/b]"
|
||||||
|
extra_formatted_values = f"Uncertainty: [b]{accuracy} meters[/b]"+updated_str
|
||||||
|
|
||||||
|
data = {"icon": s["icon"], "text": f"{formatted_values}"}
|
||||||
|
extra_entries.append({"icon": "map-marker-question", "text": extra_formatted_values})
|
||||||
|
def select(e=None):
|
||||||
|
geo_uri = f"geo:{lat},{lon}"
|
||||||
|
def lj():
|
||||||
|
webbrowser.open(geo_uri)
|
||||||
|
threading.Thread(target=lj, daemon=True).start()
|
||||||
|
|
||||||
|
release_function = select
|
||||||
|
else:
|
||||||
|
formatted_values = f"{name}:"
|
||||||
|
for vn in s["values"]:
|
||||||
|
v = s["values"][vn]
|
||||||
|
formatted_values += f" [b]{v} {vn}[/b]"
|
||||||
|
|
||||||
|
if release_function:
|
||||||
|
data = {"icon": s["icon"], "text": f"{formatted_values}", "on_release": release_function}
|
||||||
|
else:
|
||||||
|
data = {"icon": s["icon"], "text": f"{formatted_values}"}
|
||||||
|
|
||||||
|
self.entries.append(data)
|
||||||
|
for extra in extra_entries:
|
||||||
|
self.entries.append(extra)
|
||||||
|
|
||||||
|
if len(self.entries) == 0:
|
||||||
|
self.entries.append({"icon": "account-question-outline", "text": f"No information known about this peer"})
|
||||||
|
|
||||||
|
self.data = self.entries
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
layou_object_details = """
|
layou_object_details = """
|
||||||
|
#:import MDLabel kivymd.uix.label.MDLabel
|
||||||
|
#:import OneLineIconListItem kivymd.uix.list.OneLineIconListItem
|
||||||
|
#:import Button kivy.uix.button.Button
|
||||||
|
|
||||||
|
<ODView>
|
||||||
|
IconLeftWidget:
|
||||||
|
icon: root.icon
|
||||||
|
|
||||||
|
<RVDetails>:
|
||||||
|
viewclass: "ODView"
|
||||||
|
RecycleBoxLayout:
|
||||||
|
default_size: None, dp(50)
|
||||||
|
default_size_hint: 1, None
|
||||||
|
size_hint_y: None
|
||||||
|
height: self.minimum_height
|
||||||
|
orientation: "vertical"
|
||||||
|
|
||||||
MDScreen:
|
MDScreen:
|
||||||
name: "object_details_screen"
|
name: "object_details_screen"
|
||||||
|
|
||||||
|
@ -48,6 +230,7 @@ MDScreen:
|
||||||
orientation: "vertical"
|
orientation: "vertical"
|
||||||
|
|
||||||
MDTopAppBar:
|
MDTopAppBar:
|
||||||
|
id: details_bar
|
||||||
title: "Details"
|
title: "Details"
|
||||||
anchor_title: "left"
|
anchor_title: "left"
|
||||||
elevation: 0
|
elevation: 0
|
||||||
|
@ -55,29 +238,62 @@ MDScreen:
|
||||||
[['menu', lambda x: root.app.nav_drawer.set_state("open")]]
|
[['menu', lambda x: root.app.nav_drawer.set_state("open")]]
|
||||||
right_action_items:
|
right_action_items:
|
||||||
[
|
[
|
||||||
['close', lambda x: root.app.close_sub_map_action(self)],
|
['close', lambda x: root.delegate.close_action()],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
MDBoxLayout:
|
||||||
|
id: object_header
|
||||||
|
orientation: "horizontal"
|
||||||
|
spacing: dp(24)
|
||||||
|
size_hint_y: None
|
||||||
|
height: self.minimum_height
|
||||||
|
padding: dp(24)
|
||||||
|
|
||||||
|
MDIconButton:
|
||||||
|
id: object_appearance
|
||||||
|
icon: "map-marker-star-outline"
|
||||||
|
icon_color: [0,0,0,1]
|
||||||
|
md_bg_color: [1,1,1,1]
|
||||||
|
theme_icon_color: "Custom"
|
||||||
|
icon_size: dp(32)
|
||||||
|
|
||||||
|
MDLabel:
|
||||||
|
id: name_label
|
||||||
|
markup: True
|
||||||
|
text: "Object Name"
|
||||||
|
font_style: "H6"
|
||||||
|
|
||||||
|
MDBoxLayout:
|
||||||
|
id: object_header
|
||||||
|
orientation: "horizontal"
|
||||||
|
spacing: dp(24)
|
||||||
|
size_hint_y: None
|
||||||
|
height: self.minimum_height
|
||||||
|
padding: [dp(24), dp(0), dp(24), dp(12)]
|
||||||
|
|
||||||
|
MDRectangleFlatIconButton:
|
||||||
|
id: telemetry_button
|
||||||
|
icon: "content-copy"
|
||||||
|
text: "Copy Telemetry"
|
||||||
|
padding: [dp(0), dp(14), dp(0), dp(14)]
|
||||||
|
icon_size: dp(24)
|
||||||
|
font_size: dp(16)
|
||||||
|
size_hint: [1.0, None]
|
||||||
|
on_release: root.delegate.copy_telemetry(self)
|
||||||
|
disabled: False
|
||||||
|
|
||||||
|
MDRectangleFlatIconButton:
|
||||||
|
id: coordinates_button
|
||||||
|
icon: "map-marker-outline"
|
||||||
|
text: "Copy Coordinates"
|
||||||
|
padding: [dp(0), dp(14), dp(0), dp(14)]
|
||||||
|
icon_size: dp(24)
|
||||||
|
font_size: dp(16)
|
||||||
|
size_hint: [1.0, None]
|
||||||
|
on_release: root.delegate.copy_coordinates(self)
|
||||||
|
disabled: False
|
||||||
|
|
||||||
ScrollView:
|
ScrollView:
|
||||||
id: object_details_scrollview
|
id: object_details_scrollview
|
||||||
|
|
||||||
MDBoxLayout:
|
|
||||||
orientation: "vertical"
|
|
||||||
spacing: dp(48)
|
|
||||||
size_hint_y: None
|
|
||||||
height: self.minimum_height
|
|
||||||
padding: [dp(28), dp(48), dp(28), dp(16)]
|
|
||||||
|
|
||||||
MDLabel:
|
|
||||||
id: name_label
|
|
||||||
markup: True
|
|
||||||
text: "Object Name"
|
|
||||||
font_style: "H6"
|
|
||||||
|
|
||||||
MDLabel:
|
|
||||||
id: test_label
|
|
||||||
markup: True
|
|
||||||
text: "Test"
|
|
||||||
font_style: "H6"
|
|
||||||
|
|
||||||
"""
|
"""
|
Loading…
Reference in New Issue