Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions service/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pyobjc-framework-cocoa = {version = "*", platform_system = "== 'Darwin'"}
plyer = {version = "*", platform_system = "== 'Windows'"}
jsonschema = "*"
PyQt5 = "*"
zeroconf = "*"

[dev-packages]
pyinstaller = "*"
Expand Down
104 changes: 86 additions & 18 deletions service/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import time
import uuid
from PyQt5 import QtCore, QtGui, QtWidgets
from zeroconf import Zeroconf, ServiceBrowser

import common
import driver_auto as driver
Expand Down Expand Up @@ -41,7 +42,7 @@ def __safe_get_status(getter_fn, fallback_value, name, duration_limit=0.25):
# Previous return value is passed as last_status. On first call, None is passed.
# counter goes up to args.send_rate-1, then back to 0. It can be used to do stuff every X iterations.
# Before quitting, the function is called one more time with counter==-1. It sends out an "everything off" message in this case.
def loopbody(args, counter, last_status):
def loopbody(args, counter, last_status, enabled_devices):
if counter >= 0:
# Normal call
fallback_status = last_status if last_status is not None else (False, False)
Expand All @@ -67,16 +68,27 @@ def loopbody(args, counter, last_status):
# Send message if status changed, or every Xth round
if status != last_status or (counter % args.send_rate)==0:
common.log('Sending UDP message...')
for ip in args.ip:
sendudp(ip, args.port, msg)
for ip, port in enabled_devices:
sendudp(ip, port, msg)

return status

class App(QtWidgets.QApplication):
onDeviceAppeared = QtCore.pyqtSignal(str, list, int)
onDeviceDisappeared = QtCore.pyqtSignal(str)

def __init__(self, args):
QtWidgets.QApplication.__init__(self, sys.argv)
self.setQuitOnLastWindowClosed(False)

self.nearbyDevices = {}
self.onDeviceAppeared.connect(self.deviceAppeared)
self.onDeviceDisappeared.connect(self.deviceDisappeared)

self.menu = QtWidgets.QMenu()
self.devicesMenu = self.menu.addMenu("Nearby devices")
self.devicesMenu.triggered.connect(self.toggleDevice)
self.menu.addAction("Add device manually", self.addDeviceManually)
self.exitAction = self.menu.addAction("Exit", self.shutdown)

style = self.style()
Expand All @@ -92,32 +104,81 @@ def __init__(self, args):
self.last_status = None
self.icounter = itertools.cycle(itertools.islice(itertools.count(start=0), self.args.send_rate))

def getIpAddress(self):
text, ok = QtWidgets.QInputDialog.getText(None, 'CheckMeet', 'Please provide IP address of device:')
if ok:
self.args.ip.append(text)
else:
driver.show_notification(APPNAME, 'Could not start service')
sys.exit(1) # can't use self.exit() here because the Qt event loop is not running yet

def start(self):
if len(self.args.ip)==0:
self.getIpAddress()

self.onTick()
self.timer.start(self.args.query_interval*1000)
self.trayIcon.show()
driver.show_notification(APPNAME, 'Service started!✨')

if len(self.args.ip) > 0:
self.deviceAppeared(f"[Added on command line]", self.args.ip, self.args.port)

def onTick(self):
counter = next(self.icounter)
self.last_status = loopbody(self.args, counter, self.last_status)
self.last_status = loopbody(self.args, counter, self.last_status, self.getEnabledDevices())

def shutdown(self):
loopbody(self.args, -1, self.last_status)
loopbody(self.args, -1, self.last_status, self.getEnabledDevices())
common.log('Shutting down')
self.exit()

def deviceAppeared(self, name, addresses, port):
print(f"deviceAppeared {name} {addresses} {port}")
if name in self.nearbyDevices:
print(f"Duplicate device {name}")
return

updatesEnabled = True
self.nearbyDevices[name] = {
'addresses': addresses,
'port': port,
'updatesEnabled': updatesEnabled,
}
a = self.devicesMenu.addAction(f"{name} {addresses}:{port}")
a.setCheckable(True)
a.setChecked(updatesEnabled)
self.nearbyDevices[name]['action'] = a

def deviceDisappeared(self, name):
print(f"deviceDisappeared {name}")
if name not in self.nearbyDevices:
print(f"Device not found {name}")
return

self.devicesMenu.removeAction(self.nearbyDevices[name]['action'])
del self.nearbyDevices[name]

def toggleDevice(self, action):
if action.isCheckable():
self.nearbyDevices[action.text()]["updatesEnabled"] = action.isChecked()

def getEnabledDevices(self):
result = []

for _, device in self.nearbyDevices.items():
if device['updatesEnabled']:
for ip in device['addresses']:
result.append((ip, device['port']))

return result

def addDeviceManually(self):
text, ok = QtWidgets.QInputDialog.getText(None, 'CheckMeet', 'Please provide IP address of device:')
if ok:
self.deviceAppeared(f"[Manually added]", [text], self.args.port)

def add_service(self, zeroconf, serviceType, name):
info = zeroconf.get_service_info(serviceType, name)
self.onDeviceAppeared.emit(info.server, info.parsed_addresses(), info.port)

def remove_service(self, zeroconf, serviceType, name):
info = zeroconf.get_service_info(serviceType, name)
self.onDeviceDisappeared.emit(info.server)

def update_service(self, zeroconf, serviceType, name):
pass


def main():
parser = argparse.ArgumentParser(description='Service')
parser.add_argument('--port', default=26999, type=int, help='Use UDP port')
Expand All @@ -127,9 +188,16 @@ def main():
parser.add_argument('ip', nargs='*', help='Send UDP packets to these IP adresses')
args = parser.parse_args()

zconf = Zeroconf()
app = App(args)
app.start()
sys.exit(app.exec_())
ServiceBrowser(zconf, "_checkmeet._udp.local.", app)
try:
app.start()
exit_status = app.exec_()
finally:
zconf.close()

sys.exit(exit_status)

if __name__ == '__main__':
main()