Skip to content

Commit

Permalink
Persist pair and bring back SMS chatty notifications (#79)
Browse files Browse the repository at this point in the history
* add 'keep paired' checkbox button (not functional)

* Getting persistant pairing working (#64)

* persistent pairing

* Minor ui tweak

* sync persist-pair with what's in main (#76)

* Add complete dependency list on Ubuntu (#55)

In order to figure this out (and make sure I was correct) I used a Docker container. By design it's awkward to support dbus & bluetooth from within a container, so totally understandable if you'd prefer to not include the Dockerfile in the repo.

I managed to get the app to run and print out "Bluetooth is disabled" which exercises a decent bit of the code. If this is helpful, it could be the start of some light CI/GitHub workflows to run some testing for PRs.

Co-authored-by: Alex R <[email protected]>

* change app-id to com.github.alexr4535.siglo for flathub

* update manifest for flathub

* bump tag

* Update com.github.alexr4535.siglo.json

* add python3-modules.json

* reference python3-requests in manifest

* prepare for next release

* use --system-talk-name to specify dbus name

* Install the required Python packages in the Flatpak manifest (#61)

* Prepare for next release

* Appdata: Add missing XML tags required by flathub

* Appdata: Add screenshot required by flathub

* bump version for next release

* fix typo

* bump version for next release

* bump version for next release

* Appdata: fix screenshot URL required by flathub

* bump version for next release

* Adding custom form_factor values (#67)

This should make Siglo show up in the PureOS Store on the Librem 5

* Adding X-Purism-FormFactor (#66)

This should help with showing up on the main app launcher of Phosh > 0.12.
For details read https://linmob.net/phosh-0-12-app-drawer/

* Fix metadata file (#68)

Fixes #65

* Bump version for next release

* Fix crash without network access (#69)

This allows Siglo to start when internet access is not available, either
because the user is outside service or the flatpak permission has been
disabled.

Co-authored-by: undef <[email protected]>

* Add requirements section and flathub install instructions

* Version Bump

Co-authored-by: Joe Smith <[email protected]>
Co-authored-by: Jordan Williams <[email protected]>
Co-authored-by: 1peter10 <[email protected]>
Co-authored-by: TheEvilSkeleton <[email protected]>
Co-authored-by: Undef-a <[email protected]>
Co-authored-by: undef <[email protected]>

* Notifications service into persist-pair branch (#77)

* Add complete dependency list on Ubuntu (#55)

In order to figure this out (and make sure I was correct) I used a Docker container. By design it's awkward to support dbus & bluetooth from within a container, so totally understandable if you'd prefer to not include the Dockerfile in the repo.

I managed to get the app to run and print out "Bluetooth is disabled" which exercises a decent bit of the code. If this is helpful, it could be the start of some light CI/GitHub workflows to run some testing for PRs.

Co-authored-by: Alex R <[email protected]>

* change app-id to com.github.alexr4535.siglo for flathub

* update manifest for flathub

* bump tag

* Update com.github.alexr4535.siglo.json

* add python3-modules.json

* reference python3-requests in manifest

* prepare for next release

* use --system-talk-name to specify dbus name

* Install the required Python packages in the Flatpak manifest (#61)

* Prepare for next release

* Appdata: Add missing XML tags required by flathub

* Appdata: Add screenshot required by flathub

* bump version for next release

* fix typo

* bump version for next release

* bump version for next release

* Appdata: fix screenshot URL required by flathub

* bump version for next release

* Adding custom form_factor values (#67)

This should make Siglo show up in the PureOS Store on the Librem 5

* Adding X-Purism-FormFactor (#66)

This should help with showing up on the main app launcher of Phosh > 0.12.
For details read https://linmob.net/phosh-0-12-app-drawer/

* Fix metadata file (#68)

Fixes #65

* Bump version for next release

* Add notification service

This allows notifications to be sent from the standard application
rather than only through the daemon. This version should be more stable
as it includes the connection improvments of the main Siglo application.

Co-authored-by: Joe Smith <[email protected]>
Co-authored-by: Jordan Williams <[email protected]>
Co-authored-by: 1peter10 <[email protected]>
Co-authored-by: TheEvilSkeleton <[email protected]>
Co-authored-by: undef <[email protected]>

* Revert "Notifications service into persist-pair branch (#77)" (#78)

This reverts commit 3f2084c.

* fixup dbus monitoring for chatty notifications

* Daemon: remove deprecated dbus eavesdropping

* stopping the daemon disconnects the device

* update systemd file

* remove my old deprecated pair switch

* Revert "remove my old deprecated pair switch"

This reverts commit 62fc823.

* remove deprecated pair switch

* remove deprecated time sync button

* remove deprecated scan functions

* delete deprecated scan functions

* delete deprecated deploy_type stuff

* fix battery and firmware version

* keep paired toggle starts the daemon

* make pair switch work with daemon

* keep paired until siglo opens again

Co-authored-by: Konstantin Quillfeldt <[email protected]>
Co-authored-by: Joe Smith <[email protected]>
Co-authored-by: Jordan Williams <[email protected]>
Co-authored-by: 1peter10 <[email protected]>
Co-authored-by: TheEvilSkeleton <[email protected]>
Co-authored-by: Undef-a <[email protected]>
Co-authored-by: undef <[email protected]>
Co-authored-by: Alex Robinson <[email protected]>
  • Loading branch information
9 people authored Sep 1, 2021
1 parent 7eddd3c commit a4eaac9
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 188 deletions.
5 changes: 3 additions & 2 deletions data/siglo.service
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[Unit]
Description=siglo service
[Service]
ExecStart=siglo --daemon
Environment=PYTHONUNBUFFERED=1
ExecStart=siglo --start
ExecStop=siglo --stop
Environment=PYTHONUNBUFFERED=1
13 changes: 8 additions & 5 deletions src/bluetooth.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ def get_scan_result(self):
return self.scan_result

def get_device_set(self):
if self.conf.get_property("paired"):
self.device_set.add(self.conf.get_property("last_paired_device"))
return self.device_set

def get_adapter_name(self):
Expand Down Expand Up @@ -108,8 +106,11 @@ def scan_for_infinitime(self):


class InfiniTimeDevice(gatt.Device):
def __init__(self, mac_address, manager):
def __init__(self, mac_address, manager, thread):
self.conf = config()
self.mac = mac_address
self.manager = manager
self.thread = thread
super().__init__(mac_address, manager)

def connect(self):
Expand All @@ -119,6 +120,8 @@ def connect(self):
def connect_succeeded(self):
super().connect_succeeded()
print("[%s] Connected" % (self.mac_address))
print("self.mac", self.mac)
self.conf.set_property("last_paired_device", self.mac)

def connect_failed(self, error):
super().connect_failed(error)
Expand Down Expand Up @@ -187,8 +190,8 @@ def services_resolved(self):

# Get device firmware
self.battery = int(battery_level.read_value()[0])

self.services_done()
if self.thread:
self.services_done()

def send_notification(self, alert_dict):
message = alert_dict["message"]
Expand Down
32 changes: 22 additions & 10 deletions src/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,39 @@ class daemon:
def __init__(self):
self.conf = config()
self.manager = InfiniTimeManager()
self.device = InfiniTimeDevice(manager=self.manager, mac_address=self.conf.get_property("last_paired_device"))
self.device.connect(sync_time=False)
self.device = InfiniTimeDevice(manager=self.manager, mac_address=self.conf.get_property("last_paired_device"), thread=False)
self.mainloop = glib.MainLoop()

def start(self):
self.device.connect()
self.scan_for_notifications()

def stop(self):
self.mainloop.quit()
self.device.disconnect()

def scan_for_notifications(self):
DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
bus.add_match_string_non_blocking(
"eavesdrop=true, interface='org.freedesktop.Notifications', member='Notify'"
)
bus.add_message_filter(self.notifications)
mainloop = glib.MainLoop()
mainloop.run()
monitor_bus = dbus.SessionBus(private=True)
try:
dbus_monitor_iface = dbus.Interface(monitor_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus'), dbus_interface='org.freedesktop.DBus.Monitoring')
dbus_monitor_iface.BecomeMonitor(["interface='org.freedesktop.Notifications', member='Notify'"], 0)
except dbus.exceptions.DBusException as e:
print(e)
return
monitor_bus.add_message_filter(self.notifications)
self.mainloop.run()

def notifications(self, bus, message):
alert_dict = {}
for arg in message.get_args_list():
if isinstance(arg, dbus.Dictionary):
if arg["desktop-entry"] == "sm.puri.Chatty":
alert_dict["category"] = "SMS"
alert_dict["sender"] = message.get_args_list()[3].split("New message from ")[1]
alert_dict["sender"] = message.get_args_list()[3]
alert_dict["message"] = message.get_args_list()[4]
alert_dict_empty = not alert_dict
if len(alert_dict) > 0:
print(alert_dict)
self.device.send_notification(alert_dict)

14 changes: 9 additions & 5 deletions src/siglo.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ gettext.install('siglo', localedir)

def main():
p = argparse.ArgumentParser(description="app to sync InfiniTime watch")
p.add_argument('--daemon', '-d', required=False, action='store_true', help="run as a service")
p.add_argument('--start', '-d', required=False, action='store_true', help="start daemon")
p.add_argument('--stop', '-x', required=False, action='store_true', help="stop daemon")
args = p.parse_args()
from siglo import daemon
d = daemon.daemon()

if args.daemon:
from siglo import daemon
d = daemon.daemon()
d.scan_for_notifications()
if args.start:
d.start()
elif args.stop:
d.stop()
else:
import gi

Expand All @@ -36,3 +39,4 @@ def main():

if __name__ == '__main__':
main()

134 changes: 25 additions & 109 deletions src/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, manager, mac, callback):
self.device = None

def run(self):
self.device = InfiniTimeDevice(manager=self.manager, mac_address=self.mac)
self.device = InfiniTimeDevice(manager=self.manager, mac_address=self.mac, thread=True)
self.device.services_done = self.data_received
self.device.connect()

Expand Down Expand Up @@ -59,6 +59,7 @@ class SigloWindow(Gtk.ApplicationWindow):
firmware_run = Gtk.Template.Child()
firmware_file = Gtk.Template.Child()
firmware_run_file = Gtk.Template.Child()
keep_paired_switch = Gtk.Template.Child()

# Flasher
dfu_stack = Gtk.Template.Child()
Expand All @@ -77,16 +78,6 @@ def __init__(self, **kwargs):
super().__init__(**kwargs)
GObject.threads_init()
self.full_list = get_quick_deploy_list()
if self.conf.get_property("deploy_type") == "manual":
self.auto_switch_deploy_type = True
self.deploy_type_switch.set_active(True)
else:
self.auto_switch_deploy_type = False
if self.conf.get_property("paired"):
self.auto_switch_paired = True
self.pair_switch.set_active(True)
else:
self.auto_switch_paired = False
GObject.signal_new(
"flash-signal",
self,
Expand All @@ -95,10 +86,14 @@ def __init__(self, **kwargs):
(GObject.TYPE_PYOBJECT,),
)

def destroy_manager(self):
if self.manager:
self.manager.stop()
self.manager = None
def disconnect_paired_device(self):
try:
devices = self.manager.devices()
for d in devices:
if d.mac_address == self.manager.get_mac_address() and d.is_connected():
d.disconnect()
finally:
self.conf.set_property("paired", "False")

def destroy_manager(self):
if self.manager:
Expand Down Expand Up @@ -134,7 +129,7 @@ def make_watch_row(self, name, mac):
grid.attach(value_mac, 2, 1, 1, 1)

arrow = Gtk.Image.new_from_icon_name("go-next-symbolic", Gtk.IconSize.BUTTON)
grid.attach(arrow, 3, 0, 1, 2)
grid.attach(arrow, 4, 0, 1, 2)

row.show_all()
return row
Expand All @@ -156,6 +151,9 @@ def do_scanning(self):
if not self.manager:
return

if self.conf.get_property("paired"):
self.disconnect_paired_device()

self.depopulate_listbox()
self.manager.scan_result = False
try:
Expand Down Expand Up @@ -194,39 +192,6 @@ def populate_assetbox(self):
for asset in get_assets_by_tag(self.tag, self.full_list):
self.ota_pick_asset_combobox.append_text(asset)

def done_scanning_multi(self, info_prefix):
if self.manager:
scan_result = self.manager.get_scan_result()
self.bt_spinner.set_visible(False)
self.rescan_button.set_visible(True)
if self.manager and scan_result:
info_suffix = "\n[INFO ] Scan Succeeded"
self.populate_listbox()
else:
info_suffix += "\n[INFO ] Scan Failed"
self.scan_fail_box.set_visible(True)
self.main_info.set_text(info_prefix + info_suffix)

def done_scanning_singleton(self, manager):
self.manager = manager
scan_result = manager.get_scan_result()
print("[INFO ] Single-Device Mode")
if scan_result:
print("[INFO ] Scan Succeeded")
print(
"[INFO ] Got watch {} on {}".format(
manager.get_mac_address(), manager.adapter_name
)
)

if self.deploy_type == "quick":
self.auto_bbox_scan_pass.set_visible(True)
if self.deploy_type == "manual":
self.bbox_scan_pass.set_visible(True)
else:
print("[INFO ] Scan Failed")
self.main_stack.set_visible_child_name("nodevice")

def callback_device_connect(self, data):
firmware, battery = data

Expand All @@ -238,9 +203,17 @@ def on_watches_listbox_row_activated(self, widget, row):
mac = row.mac
self.current_mac = mac
alias = row.alias
thread = ConnectionThread(self.manager, mac, self.callback_device_connect)
thread.daemon = True
thread.start()

if self.keep_paired_switch.get_active():
# Start daemon
subprocess.Popen(["systemctl", "--user", "start", "siglo"])
self.conf.set_property("paired", "True")

if self.manager is not None:
thread = ConnectionThread(self.manager, mac, self.callback_device_connect)
thread.daemon = True
thread.start()

self.watch_name.set_text(alias)
self.watch_address.set_text(mac)
self.main_stack.set_visible_child_name("watch")
Expand Down Expand Up @@ -283,21 +256,6 @@ def rescan_button_clicked(self, widget):
def on_bluetooth_settings_clicked(self, widget):
subprocess.Popen(["gnome-control-center", "bluetooth"])

@Gtk.Template.Callback()
def sync_time_button_clicked(self, widget):
if self.manager is not None:
print("Sync Time button clicked...")
device = InfiniTimeDevice(
manager=self.manager, mac_address=self.manager.get_mac_address()
)
device.connect(sync_time=True)
if device.successful_connection:
self.main_info.set_text("InfiniTime Sync... Success!")
else:
self.main_info.set_text("InfiniTime Sync... Failed!")
self.scan_pass_box.set_visible(False)
self.rescan_button.set_visible(True)

@Gtk.Template.Callback()
def ota_file_selected(self, widget):
filename = widget.get_filename()
Expand All @@ -307,18 +265,6 @@ def ota_file_selected(self, widget):
self.ota_selection_box.set_visible(False)
self.ota_picked_box.set_sensitive(True)

@Gtk.Template.Callback()
def ota_cancel_button_clicked(self, widget):
if self.conf.get_property("deploy_type") == "quick":
self.ota_pick_asset_combobox.remove_all()
self.ota_pick_tag_combobox.remove_all()
self.populate_tagbox()
self.ota_picked_box.set_sensitive(False)
if self.conf.get_property("deploy_type") == "manual":
self.main_info.set_text("Choose another OTA File")
self.ota_picked_box.set_visible(False)
self.ota_selection_box.set_visible(True)

@Gtk.Template.Callback()
def firmware_run_file_clicked_cb(self, widget):
self.dfu_stack.set_visible_child_name("ok")
Expand Down Expand Up @@ -403,35 +349,6 @@ def deploy_type_toggled(self, widget):
self.conf.set_property("deploy_type", "quick")
self.rescan_button.emit("clicked")

@Gtk.Template.Callback()
def pair_switch_toggled(self, widget):
self.conf.set_property("last_paired_device", self.manager.get_mac_address())
print(self.manager)
if self.conf.get_property("paired") and self.auto_switch_paired == True:
self.auto_switch_paired = False
else:
if not self.conf.get_property("paired"):
self.conf.set_property("paired", "True")
if self.manager is not None:
print("Pairing with", self.manager.get_mac_address())
device = InfiniTimeDevice(
manager=self.manager, mac_address=self.manager.get_mac_address()
)
device.connect(sync_time=True)
subprocess.call(["systemctl", "--user", "daemon-reload"])
subprocess.call(["systemctl", "--user", "restart", "siglo"])
else:
try:
device = InfiniTimeDevice(
manager=self.manager, mac_address=self.manager.get_mac_address()
)
device.disconnect()
except dbus.exceptions.DBusException:
raise BluetoothDisabled
finally:
subprocess.call(["systemctl", "--user", "daemon-reload"])
subprocess.call(["systemctl", "--user", "stop", "siglo"])
self.conf.set_property("paired", "False")

def update_progress_bar(self):
self.dfu_progress_bar.set_fraction(
Expand All @@ -454,7 +371,6 @@ def show_complete(self, success):
else:
self.main_info.set_text("OTA Update Failed")
self.bt_spinner.set_visible(False)
self.sync_time_button.set_visible(True)
self.dfu_progress_box.set_visible(False)
self.ota_picked_box.set_visible(True)
if self.conf.get_property("deploy_type") == "quick":
Expand Down
Loading

0 comments on commit a4eaac9

Please sign in to comment.