diff options
author | Edi Feschiyan <edi.feschiyan@konsulko.com> | 2020-06-12 22:44:25 +0300 |
---|---|---|
committer | Edi Feschiyan <edi.feschiyan@konsulko.com> | 2020-06-12 22:44:25 +0300 |
commit | 8a8b87e65c0b3d579f8ea420e23a9cd07528dfe1 (patch) | |
tree | d5ced56f53104781bf156b38dbad7aba48578ca1 /services | |
parent | e2bb2d3ff3f909b9417040de4dd8ea876777a6ee (diff) |
Adding cookiecutter, preparing for setuptools, new services
Diffstat (limited to 'services')
-rw-r--r-- | services/audiomixer.py | 94 | ||||
-rw-r--r-- | services/base.py | 258 | ||||
-rw-r--r-- | services/bluetooth-map.py | 0 | ||||
-rw-r--r-- | services/bluetooth-pbap.py | 0 | ||||
-rw-r--r-- | services/bluetooth.py | 96 | ||||
-rw-r--r-- | services/geoclue.py | 44 | ||||
-rw-r--r-- | services/gps.py | 56 | ||||
-rw-r--r-- | services/mediaplayer.py | 160 | ||||
-rw-r--r-- | services/network.py | 0 | ||||
-rw-r--r-- | services/nfc.py | 42 | ||||
-rw-r--r-- | services/taskmanager.py | 0 | ||||
-rw-r--r-- | services/weather.py | 48 |
12 files changed, 798 insertions, 0 deletions
diff --git a/services/audiomixer.py b/services/audiomixer.py new file mode 100644 index 0000000..e594471 --- /dev/null +++ b/services/audiomixer.py @@ -0,0 +1,94 @@ +from aglbaseservice import AGLBaseService, AFBResponse +import asyncio +import os + +verbs = ['subscribe', 'unsubscribe', 'list_controls', 'volume', 'mute'] +events = ['volume_changed', 'mute_changed', 'controls_changed'] + + +class AudioMixerService(AGLBaseService): + service = 'agl-service-audiomixer' + parser = AGLBaseService.getparser() + parser.add_argument('--list_controls', default=True, help='Request list of controls', action='store_true') + parser.add_argument('--getmute', help='Get mute state', action='store_true') + parser.add_argument('--setmute', help='Set mute state', type=int, choices=[0, 1]) + parser.add_argument('--setvolume', help='Set volume level', type=float) + parser.add_argument('--getvolume', help='Get volume level', action='store_true') + + + def __init__(self, ip, port=None, service='agl-service-audiomixer'): + super().__init__(api='audiomixer', ip=ip, port=port, service=service) + + async def subscribe(self, event='volume_changed'): # audio mixer uses 'event' instead 'value', + return await self.request('subscribe', {'event': event}) + + async def unsubscribe(self, event='volume_changed'): + return await self.request('unsubscribe', {'event': event}) + + async def list_controls(self): + return await self.request('list_controls') + + async def volume(self, control='Master', value=None): + if value is not None: + return await self.request('volume', {'control': control, 'value': value}) + else: + return await self.request('volume', {'control': control}) + + async def mute(self, value=None): + return await self.request('mute', {'control': 'Master', 'value': value}) + + +async def main(): + args = AudioMixerService.parser.parse_args() + ams = await AudioMixerService(ip=args.ipaddr, port=args.port) + + if args.list_controls: + resp = await ams.list_controls() + print(f'Requesting list_controls with id {resp}') + r = AFBResponse(await ams.response()) + print(r) + + if args.setvolume is not None: + resp = await ams.volume(args.setvolume) + print(f'Setting volume to {args.setvolume} with id {resp}') + r = AFBResponse(await ams.response()) + print(r) + + if args.getvolume: + resp = await ams.volume() + print(f'Requesting volume with id {resp}') + r = AFBResponse(await ams.response()) + print(r) + + if args.setmute is not None: + resp = await ams.mute(args.setmute) + print(f'Setting mute to {args.setmute} with id {resp}') + r = AFBResponse(await ams.response()) + print(r) + + if args.getmute: + resp = await ams.mute() + r = AFBResponse(await ams.response()) + print(r) + + if args.subscribe: + for event in args.subscribe: + id = await ams.subscribe(event) + print(f'Subscribing to {event} with id {id}') + r = AFBResponse(await ams.response()) + print(r) + + if args.unsubscribe: + for event in args.unsubscribe: + id = await ams.unsubscribe(event) + print(f'Unsubscribing from {event} with id {id}') + r = AFBResponse(await ams.response()) + print(r) + + if args.listener: + async for response in ams.listener(): + print(response) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/services/base.py b/services/base.py new file mode 100644 index 0000000..03d4793 --- /dev/null +++ b/services/base.py @@ -0,0 +1,258 @@ +from json import JSONDecodeError +from parse import Result, parse +from websockets import connect +from random import randint +from enum import IntEnum +from typing import Union +import asyncssh +import argparse +import asyncio +import binascii +import logging +import json +import sys +import os +import re + +# logging.getLogger('AGLBaseService') +# logging.basicConfig(level=logging.DEBUG) + +# AFB message type +class AFBT(IntEnum): + REQUEST = 2, + RESPONSE = 3, + ERROR = 4, + EVENT = 5 + +msgq = {} +AFBLEN = 3 + + +def newrand(): + while True: + bs = os.urandom(5) + result = bs[0] * bs[1] * bs[2] * bs[3] + bs[4] + yield result + +def addrequest(msgid, msg): + msgq[msgid] = {'request': msg, 'response': None} + +def addresponse(msgid, msg): + if msgid in msgq.keys(): + msgq[msgid]['response'] = msg + +class AFBResponse: + type: AFBT + msgid: int + data: dict + api: str + status: str + info: str + + def __init__(self, data: list): + if type(data[0]) is not int: + logging.debug(f'Received a response with non-integer message type {binascii.hexlify(data[0])}') + raise ValueError('Received a response with non-integer message type') + if data[0] not in AFBT._value2member_map_: + raise ValueError(f'Received a response with invalid message type {data[0]}') + self.type = AFBT(data[0]) + + if self.type == AFBT.RESPONSE: + if 'request' not in data[2]: + logging.error(f'Received malformed or invalid response without "request" dict - {data}') + if not str.isnumeric(data[1]): + raise ValueError(f'Received a response with non-numeric message id {data[1]}') + else: + self.msgid = int(data[1]) + self.status = data[2]['request']['status'] + if 'info' in data[2]['request']: + self.info = data[2]['request']['info'] + if 'response' in data[2]: + self.data = data[2]['response'] + + elif self.type == AFBT.EVENT: + self.api = data[1] + if 'data' in data[2]: + self.data = data[2]['data'] + + elif self.type == AFBT.ERROR: + logging.debug(f'AFB returned erroneous response {data}') + self.msgid = int(data[1]) + self.status = data[2]['request']['status'] + self.info = data[2]['request']['info'] + # raise ValueError(f'AFB returned erroneous response {data}') + # if 'request' not in data[2] or 'response' not in data[2]: + + if 'response' in data[2]: + self.data = data[2]['response'] + + def __str__(self): # for debugging purposes + if self.type == AFBT.EVENT: + return f'[{self.type.name}][{self.api}][Data: {self.data if hasattr(self, "data") else None}]' + else: + return f'[{self.type.name}][Status: {self.status}][{self.msgid}]' \ + f'[Info: {self.info if hasattr(self,"info") else None}]' \ + f'[Data: {self.data if hasattr(self, "data") else None}]' + + +class AGLBaseService: + api: str + url: str + ip : str + port = None + token: str + uuid: str + service = None + logger = None + + @staticmethod + def getparser(): + parser = argparse.ArgumentParser(description='Utility to interact with agl-service-* via it\'s websocket') + parser.add_argument('-l', '--loglevel', help='Level of logging verbosity', default='INFO', + choices=list(logging._nameToLevel.keys())) + parser.add_argument('ipaddr', default=os.environ.get('AGL_TGT_IP', 'localhost'), help='AGL host address') + parser.add_argument('--port', default=os.environ.get('AGL_TGT_PORT', None), help=f'AGL service websocket port') + parser.add_argument('--listener', default=False, help='Register a listener for incoming events', action='store_true') + parser.add_argument('--subscribe', type=str, help='Subscribe to event type', action='append', metavar='event') + parser.add_argument('--unsubscribe', type=str, help='Unsubscribe from event type', action='append', metavar='event') + parser.add_argument('--json', type=str, help='Send your own json string') + parser.add_argument('--verb', type=str, help='Send the json above to specific verb') + parser.add_argument('--api', type=str, help='Send the above two to a specific api') + return parser + + def __init__(self, api: str, ip: str, port: str = None, url: str = None, + token: str = 'HELLO', uuid: str = 'magic', service: str = None): + self.api = api + self.url = url + self.ip = ip + self.port = port + self.token = token + self.uuid = uuid + self.service = service + self.logger = logging.getLogger(service) + + def __await__(self): + return self._async_init().__await__() + + async def __aenter__(self): + return self._async_init() + + async def _async_init(self): + # setting ping_interval to None because AFB does not support websocket ping + # if set to !None, the library will close the socket after the default timeout + if self.port is None: + serviceport = await self.portfinder() + if serviceport is not None: + self.port = serviceport + else: + self.logger.error('Unable to find port') + exit(1) + + URL = f'ws://{self.ip}:{self.port}/api?token={self.token}&uuid={self.uuid}' + self._conn = connect(close_timeout=0, uri=URL, subprotocols=['x-afb-ws-json1'], ping_timeout=None, compression=None) + self.websocket = await self._conn.__aenter__() + return self + + async def __aexit__(self, *args, **kwargs): + await self._conn.__aexit__(*args, **kwargs) + + async def close(self): + await self._conn.__aexit__(*sys.exc_info()) + + async def send(self, message): + await self.websocket.send(message) + + async def receive(self): + return await self.websocket.recv() + + async def portfinder(self): + # TODO:handle ssh timeouts, asyncssh does not support it apparently, and connect returns context_manager which + # cannot be used with asyncio.wait_for + + async with asyncssh.connect(self.ip, username='root') as c: + + servicename = await c.run(f"systemctl --all | grep {self.service}-- | awk '{{print $1}}'", check=False) + if self.service not in servicename.stdout: + logging.error(f"Service matching pattern - '{self.service}' - NOT FOUND") + exit(1) + pidres = await c.run(f'systemctl show --property MainPID --value {servicename.stdout.strip()}') + pid = int(pidres.stdout.strip(), 10) + if pid is 0: + logging.warning(f'Service {servicename.stdout.strip()} is stopped') + return None + else: + self.logger.debug(f'Service PID: {str(pid)}') + + sockets = await c.run(f'find /proc/{pid}/fd/ | xargs readlink | grep socket') + inodes = frozenset(re.findall("socket:\\[(.*)\\]", sockets.stdout)) + self.logger.debug(f"Socket inodes: {inodes}") + + procnettcp = await c.run('cat /proc/net/tcp') + fieldsstr = '{sl}: {local_address} {rem_address} {st} {tx_queue}:{rx_queue} {tr}:{tmwhen} {retrnsmt} {uid}'\ + ' {timeout} {inode} {sref_cnt} {memloc} {rto} {pred_sclk} {ackquick} {congest} {slowstart}' + tcpsockets = [' '.join(l.split()) for l in procnettcp.stdout.splitlines()[1:]] + # different lines with less stats appear sometimes, parse will return None, so ignore 'None' lines + parsedtcpsockets = [] + for l in tcpsockets: + res = parse(fieldsstr, l) + if isinstance(res, Result): + parsedtcpsockets.append(res) + + socketinodesbythisprocess = [l for l in parsedtcpsockets if + isinstance(l, Result) and + l.named['inode'] in inodes and + # 0A is listening state for the socket + l.named['st'] == '0A'] + + for s in socketinodesbythisprocess: + _, port = tuple(parse('{}:{}', s['local_address'])) + port = int(port, 16) + if port >= 30000: # the port is above 30000 range, 8080 is some kind of proxy + self.logger.debug(f'Service running at port {port}') + return port + + async def listener(self, stdout: bool = False): + while True: + raw = await self.response() + data = AFBResponse(raw) + if stdout: print(data) + yield data + + async def response(self): + try: + msg = await self.websocket.recv() + try: + data = json.loads(msg) + self.logger.debug('[AGL] -> ' + msg) + if isinstance(data, list): + # check whether the received response is an answer to previous query and queue it for debugging + if len(data) == AFBLEN and data[0] == AFBT.RESPONSE and str.isnumeric(data[1]): + msgid = int(data[1]) + if msgid in msgq: + addresponse(msgid, data) + return data + except JSONDecodeError: + self.logger.warning("Not decoding a non-json message") + + except KeyboardInterrupt: + self.logger.debug("Received keyboard interrupt, exiting") + except asyncio.CancelledError: + self.logger.warning("Websocket listener coroutine stopped") + except Exception as e: + self.logger.error("Unhandled seal: " + str(e)) + + async def afbresponse(self): + return AFBResponse(await self.response()) + + async def request(self, verb: str, values: Union[str, dict] = "", msgid: int = None): + msgid = next(newrand()) if msgid is None else msgid + l = json.dumps([AFBT.REQUEST, str(msgid), f'{self.api}/{verb}', values]) + self.logger.debug(f'[AGL] <- {l}') + await self.send(l) + return msgid + + async def subscribe(self, event): + return await self.request('subscribe', {'value': f'{event}'}) # some services may use 'event' instead 'value' + + async def unsubscribe(self, event): + return await self.request('unsubscribe', {'value': f'{event}'}) diff --git a/services/bluetooth-map.py b/services/bluetooth-map.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/services/bluetooth-map.py diff --git a/services/bluetooth-pbap.py b/services/bluetooth-pbap.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/services/bluetooth-pbap.py diff --git a/services/bluetooth.py b/services/bluetooth.py new file mode 100644 index 0000000..b73f8a8 --- /dev/null +++ b/services/bluetooth.py @@ -0,0 +1,96 @@ +from aglbaseservice import AGLBaseService, AFBResponse +import asyncio +import os + +Verbs = ['subscribe', 'unsubscribe', 'managed_objects', 'adapter_state', 'default_adapter', 'avrcp_controls', + 'connect', 'disconnect', 'pair', 'cancel_pairing', 'confirm_pairing', 'remove_device'] +AdapterStateParams = ['discovery', 'discoverable', 'powered', ] + +BTEventType = ['adapter_changes', 'device_changes', 'media', 'agent'] + + +class BluetoothService(AGLBaseService): + service = 'agl-service-bluetooth' + parser = AGLBaseService.getparser() + parser.add_argument('--default_adapter', help='Get default bluetooth adapter', action='store_true') + parser.add_argument('--managed_objects', help='Get managed objects', action='store_true') + parser.add_argument('--adapter', help='Select remote adapter', required=False, default='hci0') + parser.add_argument('--adapter_state') + parser.add_argument('--connect', help='Connect to device', metavar='dev_88_0F_10_96_D3_20') + parser.add_argument('--disconnect', help='Disconnect from device', metavar='dev_88_0F_10_96_D3_20') + parser.add_argument('--pair', help='Pair with a device', metavar='dev_88_0F_10_96_D3_20') + parser.add_argument('--cancel_pairing', help='Cancel ongoing pairing') + parser.add_argument('--confirm_pairing', metavar='pincode') + parser.add_argument('--remove_device', metavar='dev_88_0F_10_96_D3_20', help='Remove paired device') + + + + def __init__(self, ip, port=None, service='agl-service-bluetooth'): + super().__init__(api='Bluetooth-Manager', ip=ip, port=port, service=service) + + async def subscribe(self, event='device_changes'): + await super().subscribe(event=event) + + async def unsubscribe(self, event='device_changes'): + await super().unsubscribe(event=event) + + async def managed_objects(self): + return await self.request('managed_objects') + + async def adapter_state(self, adapter=None, value=None): + p = {} + if adapter: + p = {'adapter': adapter} + if isinstance(value, dict): + p = {**p, **value} + + return await self.request('adapter_state', p) + + async def default_adapter(self): + return await self.request('default_adapter', "") + + async def connect(self, device: str = 'hci0'): + return await self.request('connect', {'device': device}) + + async def disconnect(self, device: str = 'hci0'): + return await self.request('disconnect', {'device': device}) + + async def pair(self, device): + return await self.request('pair', {'device': device}) + + async def cancel_pairing(self): + return await self.request('cancel_pairing') + + async def confirm_pairing(self, pincode): + return await self.request('confirm_pairing', {'pincode': pincode}) + + async def remove_device(self, device): + return await self.request('remove_device', {'device': device}) + + async def avrcp_controls(self): + pass + +async def main(loop): + args = BluetoothService.parser.parse_args() + bts = await BluetoothService(ip=args.ipaddr, port=args.port) + + if args.default_adapter: + id = await bts.default_adapter() + print(f'Requesting default adapter with id {id}') + r = AFBResponse(await bts.response()) + print(r) + + if args.adapter_state: + pass + + if args.listener: + for response in bts.listener(): + print(response) + + bts.logger.debug(await bts.adapter_state('hci0', {'uuids': ['0000110e-0000-1000-8000-00805f9b34fb']})) + + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main(loop)) diff --git a/services/geoclue.py b/services/geoclue.py new file mode 100644 index 0000000..df1afd6 --- /dev/null +++ b/services/geoclue.py @@ -0,0 +1,44 @@ +from aglbaseservice import AGLBaseService, AFBResponse +import asyncio +import os + + +class GeoClueService(AGLBaseService): + service = 'agl-service-geoclue' + parser = AGLBaseService.getparser() + parser.add_argument('--location', help='Get current location', action='store_true') + + def __init__(self, ip, port=None, api='geoclue'): + super().__init__(ip=ip, port=port, api=api, service='agl-service-geoclue') + + async def location(self): + return await self.request('location') + + async def subscribe(self, event='location'): + return await super().subscribe(event=event) + + async def unsubscribe(self, event='location'): + return await super().unsubscribe(event=event) + + +async def main(loop): + args = GeoClueService.parser.parse_args() + gcs = await GeoClueService(args.ipaddr) + + if args.location: + id = await gcs.location() + print(f'Sent location request with messageid {id}') + print(AFBResponse(await gcs.response())) + + if args.subscribe: + for event in args.subscribe: + id = await gcs.subscribe(event) + print(f"Subscribed for {event} with messageid {id}") + print(AFBResponse(await gcs.response())) + if args.listener: + async for response in gcs.listener(): + print(response) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main(loop)) diff --git a/services/gps.py b/services/gps.py new file mode 100644 index 0000000..1905e0f --- /dev/null +++ b/services/gps.py @@ -0,0 +1,56 @@ +from aglbaseservice import AGLBaseService, AFBResponse +import asyncio +import os + + +class GPSService(AGLBaseService): + service = 'agl-service-gps' + parser = AGLBaseService.getparser() + parser.add_argument('--record', help='Begin recording verb ') + parser.add_argument('--location', help='Get current location', action='store_true') + + def __init__(self, ip, port=None): + super().__init__(api='gps', ip=ip, port=port, service='agl-service-gps') + + async def location(self): + return await self.request('location') + + async def record(self, state='on'): + return await self.request('record', {'state': state}) + + async def subscribe(self, event='location'): + return await super().subscribe(event=event) + + async def unsubscribe(self, event='location'): + return await super().subscribe(event=event) + + +async def main(loop): + args = GPSService.parser.parse_args() + gpss = await GPSService(ip=args.ipaddr, port=args.port) + + if args.loglevel: + gpss.logger.setLevel(args.loglevel) + + if args.record: + id = await gpss.record(args.record) + print(f'Sent gps record request with value {args.record} with messageid {id}') + print(AFBResponse(await gpss.response())) + + if args.location: + msgid = await gpss.location() + print(AFBResponse(await gpss.response())) + + if args.subscribe: + for event in args.subscribe: + id = await gpss.subscribe(event) + print(f'Subscribed for event {event} with messageid {id}') + print(AFBResponse(await gpss.response())) + + if args.listener: + async for response in gpss.listener(): + print(response) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main(loop)) diff --git a/services/mediaplayer.py b/services/mediaplayer.py new file mode 100644 index 0000000..9291981 --- /dev/null +++ b/services/mediaplayer.py @@ -0,0 +1,160 @@ +from aglbaseservice import AGLBaseService, AFBResponse +from typing import Union +import logging +import asyncio +import os + +class AFBMediaPlayerResponse(AFBResponse): + status: str + info: str + data = None + + def __init__(self, data: AFBResponse): + if isinstance(data, list): + super().__init__(data) + self.msgid = data.msgid + self.type = data.type + self.data = data.data + + +class MediaPlayerService(AGLBaseService): + service = 'agl-service-mediaplayer' + parser = AGLBaseService.getparser() + parser.add_argument('--playlist', help='Get current playlist', action='store_true') + parser.add_argument('--control', help='Play/Pause/Previous/Next') + parser.add_argument('--seek', help='Seek time through audio track', metavar='msec', type=int) + parser.add_argument('--rewind', help='Rewind time', metavar='msec', type=int) + parser.add_argument('--fastforward', help='Fast forward time', metavar='msec', type=int) + parser.add_argument('--picktrack', help='Play specific track in the playlist', metavar='index', type=int) + parser.add_argument('--volume', help='Volume control - <1-100>', metavar='int') + parser.add_argument('--loop', help='Set loop state - <off/track/playlist>', metavar='string') + parser.add_argument('--avrcp', help='AVRCP Controls') + def __await__(self): + return super()._async_init().__await__() + + def __init__(self, ip, port=None): + super().__init__(api='mediaplayer', ip=ip, port=port, service='agl-service-mediaplayer') + + async def playlist(self): + return await self.request('playlist') + + async def subscribe(self, event='metadata'): + return await super().subscribe(event=event) + + async def unsubscribe(self, event='metadata'): + return await super().subscribe(event=event) + + async def control(self, name, value=None): + loopstate = ['off', 'playlist', 'track'] + avrcp_controls = ['next', 'previous', 'play', 'pause'] + controls = { + 'play': None, + 'pause': None, + 'previous': None, + 'next': None, + 'seek': 'position', + 'fast-forward': 'position', + 'rewind': 'position', + 'pick-track': 'index', + 'volume': 'volume', + 'loop': 'state', + # 'avrcp_controls': 'value' + } + assert name in controls.keys(), f'Tried to use non-existent {name} as control for {self.api}' + msg = None + if name in ['play', 'pause', 'previous', 'next']: + msg = {'value': name} + elif name in ['seek', 'fast-forward', 'rewind']: + #assert value > 0, "Tried to seek with negative integer" + msg = {'value': name, controls[name]: str(value)} + elif name == 'pick-track': + assert type(value) is int, "Try picking a song with an integer" + assert value > 0, "Tried to pick a song with a negative integer" + msg = {'value': name, controls[name]: str(value)} + elif name == 'volume': + assert type(value) is int, "Try setting the volume with an integer" + assert value > 0, "Tried to set the volume with a negative integer, use values betwen 0-100" + assert value < 100, "Tried to set the volume over 100%, use values betwen 0-100" + msg = {'value': name, name: str(value)} + elif name == 'loop': + assert value in loopstate, f'Tried to set invalid loopstate - {value}, use "off", "playlist" or "track"' + msg = {'value': name, controls[name]: str(value)} + # elif name == 'avrcp_controls': + # msg = {'value': name, } + assert msg is not None, "Congratulations, somehow you made an invalid control request" + + return await self.request('controls', msg) + + +async def main(loop): + args = MediaPlayerService.parser.parse_args() + MPS = await MediaPlayerService(ip=args.ipaddr) + + if args.playlist: + id = await MPS.playlist() + r = AFBResponse(await MPS.response()) + for l in r.data['list']: print(l) + + if args.control: + id = await MPS.control(args.control) + print(f'Sent {args.control} request with messageid {id}') + r = AFBResponse(await MPS.response()) + print(r) + + if args.seek: + id = await MPS.control('seek', args.seek) + print(f'Sent seek request to {args.seek} msec with messageid {id}') + r = AFBResponse(await MPS.response()) + print(r) + + if args.fastforward: + id = await MPS.control('fast-forward', args.fastforward) + print(f'Sent fast-forward request for {args.fastforward} msec with messageid {id}') + r = AFBResponse(await MPS.response()) + print(r) + + if args.rewind: + id = await MPS.control('rewind', -args.rewind) + print(f'Sent rewind request for {args.rewind} msec with messageid {id}') + r = AFBResponse(await MPS.response()) + print(r) + + if args.picktrack: + id = await MPS.control('pick-track', args.picktrack) + print(f'Sent pick-track request with index {args.rewind} with messageid {id}') + r = AFBResponse(await MPS.response()) + print(r) + + if args.volume: + id = await MPS.control('volume', int(args.volume)) + print(f'Sent volume request: {args.rewind} with messageid {id}') + r = AFBResponse(await MPS.response()) + print(r) + + if args.loop: + id = await MPS.control('loop', args.loop) + print(f'Sent loop-state request: {args.loop} with messageid {id}') + r = AFBResponse(await MPS.response()) + print(r) + + # if args.avrcp: + # id = await MPS.control('avrcp_controls', args.avrcp) + # print(f'Sent AVRCP control request: {args.loop} with messageid {id}') + # r = AFBResponse(await MPS.response()) + # print(r) + + if args.subscribe: + for event in args.subscribe: + id = await MPS.subscribe(event) + print(f"Subscribed for event {event} with messageid {id}") + r = await MPS.response() + print(r) + + if args.listener: + async for response in MPS.listener(): + print(response) + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main(loop)) diff --git a/services/network.py b/services/network.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/services/network.py diff --git a/services/nfc.py b/services/nfc.py new file mode 100644 index 0000000..c966c4a --- /dev/null +++ b/services/nfc.py @@ -0,0 +1,42 @@ +from aglbaseservice import AGLBaseService, AFBResponse +import asyncio + +class NFCService(AGLBaseService): + service = 'agl-service-nfc' + parser = AGLBaseService.getparser() + + def __init__(self, ip, port=None, api='nfc'): + super().__init__(ip=ip, port=port, api=api, service='agl-service-nfc') + + async def subscribe(self, event='presence'): + return await super().subscribe(event=event) + + async def unsubscribe(self, event='presence'): + return await super().unsubscribe(event=event) + + +async def main(loop): + args = NFCService.parser.parse_args() + nfcs = await NFCService(ip=args.ipaddr, port=args.port) + + if args.subscribe: + for event in args.subscribe: + id = await nfcs.subscribe(event) + print(f"Subscribing for event {event} with messageid {id}") + r = AFBResponse(await nfcs.response()) + print(r) + + if args.unsubscribe: + for event in args.unsubscribe: + id = await nfcs.unsubscribe(event) + print(f"Unsubscribing for event {event} with messageid {id}") + r = AFBResponse(await nfcs.response()) + print(r) + + if args.listener: + async for response in nfcs.listener(): + print(response) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main(loop)) diff --git a/services/taskmanager.py b/services/taskmanager.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/services/taskmanager.py diff --git a/services/weather.py b/services/weather.py new file mode 100644 index 0000000..f3c02d0 --- /dev/null +++ b/services/weather.py @@ -0,0 +1,48 @@ +import asyncio +import json +from aglbaseservice import AGLBaseService, AFBResponse + + +class WeatherService(AGLBaseService): + service = 'agl-service-weather' + parser = AGLBaseService.getparser() + parser.add_argument('--current', default=True, help='Request current weather state', action='store_true') + parser.add_argument('--apikey', default=False, help='Request weather API Key', action='store_true') + + def __init__(self, ip, port=None): + super().__init__(api='weather', ip=ip, port=port, service='agl-service-weather') + + async def current_weather(self): + return await self.request('current_weather', "") + + async def apikey(self): + return await self.request('api_key', "") + + +async def main(): + args = WeatherService.parser.parse_args() + aws = await WeatherService(ip=args.ipaddr, port=args.port) + if args.current: + id = await aws.current_weather() + resp = AFBResponse(await aws.response()) + print(json.dumps(resp.data, indent=2)) + + if args.apikey: + id = await aws.apikey() + resp = AFBResponse(await aws.response()) + print(resp.data['api_key']) + + if args.subscribe: + for event in args.subscribe: + id = await aws.subscribe(event) + print(f'Subscribed for event {event} with messageid {id}') + resp = AFBResponse(await aws.response()) + print(resp) + + if args.listener: + async for response in aws.listener(): + print(response) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) |