diff --git a/sbapp/buildozer.spec b/sbapp/buildozer.spec index 4757275..b4a882b 100644 --- a/sbapp/buildozer.spec +++ b/sbapp/buildozer.spec @@ -25,7 +25,7 @@ android.presplash_color = #00000000 orientation = portrait fullscreen = 0 -android.permissions = INTERNET,POST_NOTIFICATIONS,WAKE_LOCK,FOREGROUND_SERVICE,CHANGE_WIFI_MULTICAST_STATE,BLUETOOTH_CONNECT,ACCESS_NETWORK_STATE,ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION,ACCESS_BACKGROUND_LOCATION +android.permissions = INTERNET,POST_NOTIFICATIONS,WAKE_LOCK,FOREGROUND_SERVICE,CHANGE_WIFI_MULTICAST_STATE,BLUETOOTH_CONNECT,ACCESS_NETWORK_STATE,ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION android.api = 30 android.minapi = 24 android.ndk = 25b diff --git a/sbapp/main.py b/sbapp/main.py index b8cbccd..1530054 100644 --- a/sbapp/main.py +++ b/sbapp/main.py @@ -2824,7 +2824,7 @@ class SidebandApp(MDApp): self.root.ids.telemetry_icon_preview.icon = self.sideband.config["telemetry_icon"] self.root.ids.telemetry_enabled.active = self.sideband.config["telemetry_enabled"] - self.root.ids.telemetry_enabled.bind(active=self.telemetry_save) + self.root.ids.telemetry_enabled.bind(active=self.telemetry_enabled_toggle) self.root.ids.telemetry_send_to_collector.active = self.sideband.config["telemetry_send_to_collector"] self.root.ids.telemetry_send_to_collector.bind(active=self.telemetry_save) @@ -2880,6 +2880,13 @@ class SidebandApp(MDApp): self.sideband.save_configuration() + def telemetry_enabled_toggle(self, sender=None, event=None): + self.telemetry_save() + if self.root.ids.telemetry_enabled.active: + self.sideband.run_telemetry() + else: + self.sideband.stop_telemetry() + def telemetry_location_toggle(self, sender=None, event=None): if self.root.ids.telemetry_s_location.active: if not check_permission("android.permission.ACCESS_COARSE_LOCATION") or not check_permission("android.permission.ACCESS_FINE_LOCATION"): @@ -2939,9 +2946,9 @@ class SidebandApp(MDApp): def telemetry_copy(self, sender=None): Clipboard.copy(str(self.sideband.get_telemetry())) - def telemetry_update(self, sender=None): + def telemetry_send_update(self, sender=None): # TODO: Implement - pass + Clipboard.copy(str(self.sideband.get_packed_telemetry())) def telemetry_fg_color(self, sender=None): color_picker = MDColorPicker(size_hint=(0.85, 0.85)) diff --git a/sbapp/sideband/core.py b/sbapp/sideband/core.py index 4091e6b..a74dba4 100644 --- a/sbapp/sideband/core.py +++ b/sbapp/sideband/core.py @@ -72,6 +72,7 @@ class SidebandCore(): SERVICE_JOB_INTERVAL = 1 PERIODIC_JOBS_INTERVAL = 60 PERIODIC_SYNC_RETRY = 360 + TELEMETRY_INTERVAL = 60 IF_CHANGE_ANNOUNCE_MIN_INTERVAL = 6 # In seconds AUTO_ANNOUNCE_RANDOM_MIN = 90 # In minutes @@ -98,6 +99,8 @@ class SidebandCore(): self.reticulum = None self.webshare_server = None self.telemeter = None + self.telemetry_running = False + self.latest_telemetry = None self.app_dir = plyer.storagepath.get_home_dir()+"/.config/sideband" if self.app_dir.startswith("file://"): @@ -1378,7 +1381,24 @@ class SidebandCore(): else: self.setstate("wants.announce", True) + def run_telemetry(self): + if not self.telemetry_running: + self.telemetry_running = True + def telemetry_job(): + while self.telemetry_running: + self.update_telemetry() + time.sleep(SidebandCore.TELEMETRY_INTERVAL) + + threading.Thread(target=telemetry_job, daemon=True).start() + + def stop_telemetry(self): + self.telemetry_running = False + self.telemeter.stop_all() + def update_telemetry(self): + self.latest_telemetry = self.get_telemetry() + + def update_telemeter_config(self): if self.config["telemetry_enabled"] == True: if self.telemeter == None: self.telemeter = Telemeter() @@ -1391,9 +1411,16 @@ class SidebandCore(): self.telemeter.disable(sensor) def get_telemetry(self): - self.update_telemetry() + self.update_telemeter_config() return self.telemeter.read_all() + def get_packed_telemetry(self): + self.update_telemeter_config() + packed = self.telemeter.packed() + # TODO: Remove + RNS.log(str(packed), RNS.LOG_WARNING) + return packed + def is_known(self, dest_hash): try: source_identity = RNS.Identity.recall(dest_hash) @@ -1609,6 +1636,9 @@ class SidebandCore(): self.lxmf_announce() self.last_if_change_announce = time.time() + if self.config["telemetry_enabled"]: + self.latest_telemetry = self.run_telemetry() + self.periodic_thread = threading.Thread(target=self._periodic_jobs, daemon=True) self.periodic_thread.start() diff --git a/sbapp/sideband/sense.py b/sbapp/sideband/sense.py index 05117c7..3be8d6e 100644 --- a/sbapp/sideband/sense.py +++ b/sbapp/sideband/sense.py @@ -1,6 +1,7 @@ import RNS import time import struct +import threading from RNS.vendor import umsgpack as umsgpack @@ -30,10 +31,12 @@ class Telemeter(): return None def __init__(self, from_packed=False): - self.sids = {Sensor.SID_BATTERY: Battery, Sensor.SID_BAROMETER: Barometer, Sensor.SID_LOCATION: Location} - self.available = {"battery": Battery, "barometer": Barometer, "location": Location} + self.sids = {Sensor.SID_TIME: Time, Sensor.SID_BATTERY: Battery, Sensor.SID_BAROMETER: Barometer, Sensor.SID_LOCATION: Location} + self.available = {"time": Time, "battery": Battery, "barometer": Barometer, "location": Location} self.from_packed = from_packed self.sensors = {} + if not self.from_packed: + self.enable("time") def enable(self, sensor): if not self.from_packed: @@ -50,6 +53,11 @@ class Telemeter(): if self.sensors[sensor].active: self.sensors[sensor].stop() + def stop_all(self): + if not self.from_packed: + for sensor in self.sensors: + self.sensors[sensor].stop() + def read(self, sensor): if not self.from_packed: if sensor in self.available: @@ -74,6 +82,7 @@ class Telemeter(): def packed(self): packed = {} + packed[Sensor.SID_TIME] = int(time.time()) for sensor in self.sensors: if self.sensors[sensor].active: packed[self.sensors[sensor].sid] = self.sensors[sensor].pack() @@ -81,9 +90,10 @@ class Telemeter(): class Sensor(): SID_NONE = 0x00 - SID_BATTERY = 0x01 - SID_BAROMETER = 0x02 - SID_LOCATION = 0x03 + SID_TIME = 0x01 + SID_LOCATION = 0x02 + SID_BAROMETER = 0x03 + SID_BATTERY = 0x04 def __init__(self, sid = None, stale_time = None): self._sid = sid or Sensor.SID_NONE @@ -142,6 +152,38 @@ class Sensor(): def unpack(self, packed): return packed +class Time(Sensor): + SID = Sensor.SID_TIME + STALE_TIME = 0.1 + + 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_data(self): + self.data = {"utc":int(time.time())} + + def pack(self): + d = self.data + if d == None: + return None + else: + return d["utc"] + + def unpack(self, packed): + try: + if packed == None: + return None + else: + return {"utc": packed} + except: + return None + class Battery(Sensor): SID = Sensor.SID_BATTERY STALE_TIME = 10 @@ -235,7 +277,7 @@ class Barometer(Sensor): class Location(Sensor): SID = Sensor.SID_LOCATION - STALE_TIME = 10 + STALE_TIME = 60*5 MIN_DISTANCE = 5 ACCURACY_TARGET = 250 @@ -278,14 +320,13 @@ class Location(Sensor): def setup_sensor(self): if RNS.vendor.platformutils.is_android(): from android.permissions import request_permissions, check_permission - if not check_permission("android.permission.ACCESS_COARSE_LOCATION") or not check_permission("android.permission.ACCESS_FINE_LOCATION"): - RNS.log("Requesting location permission", RNS.LOG_DEBUG) - request_permissions(["android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"]) - self.gps.configure(on_location=self.android_location_callback) - self.gps.start(minTime=self._stale_time, minDistance=self._min_distance) + if check_permission("android.permission.ACCESS_COARSE_LOCATION") and check_permission("android.permission.ACCESS_FINE_LOCATION"): + self.gps.configure(on_location=self.android_location_callback) + self.gps.start(minTime=self._stale_time, minDistance=self._min_distance) + self.update_data() - + def teardown_sensor(self): if RNS.vendor.platformutils.is_android(): self.gps.stop() diff --git a/sbapp/ui/layouts.py b/sbapp/ui/layouts.py index 6c1a531..666382a 100644 --- a/sbapp/ui/layouts.py +++ b/sbapp/ui/layouts.py @@ -890,7 +890,7 @@ MDNavigationLayout: icon_size: dp(24) font_size: dp(16) size_hint: [1.0, None] - on_release: root.ids.screen_manager.app.telemetry_update(self) + on_release: root.ids.screen_manager.app.telemetry_send_update(self) disabled: False MDRectangleFlatIconButton: