diff --git a/app/iot/devices.py b/app/iot/devices.py index 5ee5ba6a..8b8e94bb 100644 --- a/app/iot/devices.py +++ b/app/iot/devices.py @@ -1,4 +1,4 @@ -import time +import asyncio as aio from .message import MessageType @@ -6,59 +6,71 @@ TIME_TO_SLEEP = 0.5 -# of course this code looks dumb, but imagine some real implementations of each method here +# of course this code looks dumb, +# but imagine some real implementations of each method here class HueLightDevice: - def connect(self) -> None: + async def connect(self) -> None: print("Connecting Hue Light.") - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Hue Light connected.") - def disconnect(self) -> None: + async def disconnect(self) -> None: print("Disconnecting Hue Light.") - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Hue Light disconnected.") - def send_message(self, message_type: MessageType, data: str = "") -> None: + async def send_message( + self, message_type: MessageType, data: str = "" + ) -> None: print( - f"Hue Light handling message of type {message_type.name} with data [{data}]." + f"Hue Light handling message of type" + f" {message_type.name} with data [{data}]." ) - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Hue Light received message.") class SmartSpeakerDevice: - def connect(self) -> None: + async def connect(self) -> None: print("Connecting to Smart Speaker.") - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Smart Speaker connected.") - def disconnect(self) -> None: + async def disconnect(self) -> None: print("Disconnecting Smart Speaker.") - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Smart Speaker disconnected.") - def send_message(self, message_type: MessageType, data: str = "") -> None: + async def send_message( + self, message_type: MessageType, data: str = "" + ) -> None: print( - f"Smart Speaker handling message of type {message_type.name} with data [{data}]." + f"Smart Speaker handling message of type" + f" {message_type.name} with data [{data}]." ) - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Smart Speaker received message.") class SmartToiletDevice: - def connect(self) -> None: + async def connect(self) -> None: print("Connecting to Smart Toilet.") - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Smart Toilet connected.") - def disconnect(self) -> None: + async def disconnect(self) -> None: print("Disconnecting Smart Toilet.") - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Smart Toilet disconnected.") - def send_message(self, message_type: MessageType, data: str = "") -> None: + async def send_message( + self, + message_type: MessageType, + data: str = "" + ) -> None: print( - f"Smart Toilet handling message of type {message_type.name} with data [{data}]." + f"Smart Toilet handling message of type" + f" {message_type.name} with data [{data}]." ) - time.sleep(TIME_TO_SLEEP) + await aio.sleep(TIME_TO_SLEEP) print("Smart Toilet received message.") diff --git a/app/iot/service.py b/app/iot/service.py index f12b6021..34d49c11 100644 --- a/app/iot/service.py +++ b/app/iot/service.py @@ -10,15 +10,17 @@ def generate_id(length: int = 8) -> str: # Protocol is very similar to ABC, but uses duck typing -# so devices should not inherit for it (if it walks like a duck, and quacks like a duck, it's a duck) +# so devices should not inherit for it +# (if it walks like a duck, and quacks like a duck, it's a duck) class Device(Protocol): - def connect(self) -> None: - ... # Ellipsis - similar to "pass", but sometimes has different meaning + async def connect(self) -> None: + ... # Ellipsis - similar to "pass", + # but sometimes has different meaning - def disconnect(self) -> None: + async def disconnect(self) -> None: ... - def send_message(self, message_type: MessageType, data: str) -> None: + async def send_message(self, message_type: MessageType, data: str) -> None: ... @@ -26,24 +28,24 @@ class IOTService: def __init__(self) -> None: self.devices: dict[str, Device] = {} - def register_device(self, device: Device) -> str: - device.connect() + async def register_device(self, device: Device) -> str: + await device.connect() device_id = generate_id() self.devices[device_id] = device return device_id - def unregister_device(self, device_id: str) -> None: - self.devices[device_id].disconnect() + async def unregister_device(self, device_id: str) -> None: + await self.devices[device_id].disconnect() del self.devices[device_id] def get_device(self, device_id: str) -> Device: return self.devices[device_id] - def run_program(self, program: list[Message]) -> None: + async def run_program(self, program: list[Message]) -> None: print("=====RUNNING PROGRAM======") for msg in program: - self.send_msg(msg) + await self.send_msg(msg) print("=====END OF PROGRAM======") - def send_msg(self, msg: Message) -> None: - self.devices[msg.device_id].send_message(msg.msg_type, msg.data) + async def send_msg(self, msg: Message) -> None: + await self.devices[msg.device_id].send_message(msg.msg_type, msg.data) diff --git a/app/main.py b/app/main.py index 33b8f3d3..586bcc65 100644 --- a/app/main.py +++ b/app/main.py @@ -1,11 +1,22 @@ import time +import asyncio as aio +from collections.abc import Awaitable from iot.devices import HueLightDevice, SmartSpeakerDevice, SmartToiletDevice from iot.message import Message, MessageType from iot.service import IOTService -def main() -> None: +async def run_sequence(*functions: Awaitable) -> None: + for function in functions: + await function + + +async def run_parallel(*functions: Awaitable) -> None: + await aio.gather(*functions) + + +async def main() -> None: # create an IOT service service = IOTService() @@ -13,17 +24,29 @@ def main() -> None: hue_light = HueLightDevice() speaker = SmartSpeakerDevice() toilet = SmartToiletDevice() - hue_light_id = service.register_device(hue_light) - speaker_id = service.register_device(speaker) - toilet_id = service.register_device(toilet) + hue_light_id = await service.register_device(hue_light) + speaker_id = await service.register_device(speaker) + toilet_id = await service.register_device(toilet) # create a few programs wake_up_program = [ Message(hue_light_id, MessageType.SWITCH_ON), Message(speaker_id, MessageType.SWITCH_ON), - Message(speaker_id, MessageType.PLAY_SONG, "Rick Astley - Never Gonna Give You Up"), + Message( + speaker_id, + MessageType.PLAY_SONG, + "Rick Astley - Never Gonna Give You Up", + ), ] + await run_sequence( + run_parallel( + service.send_msg(wake_up_program[0]), + service.send_msg(wake_up_program[1]), + ), + service.send_msg(wake_up_program[2]), + ) + sleep_program = [ Message(hue_light_id, MessageType.SWITCH_OFF), Message(speaker_id, MessageType.SWITCH_OFF), @@ -31,14 +54,21 @@ def main() -> None: Message(toilet_id, MessageType.CLEAN), ] - # run the programs - service.run_program(wake_up_program) - service.run_program(sleep_program) + await run_sequence( + run_parallel( + service.send_msg(sleep_program[0]), + service.send_msg(sleep_program[1]), + ), + run_sequence( + service.send_msg(sleep_program[2]), + service.send_msg(sleep_program[3]), + ), + ) if __name__ == "__main__": start = time.perf_counter() - main() + aio.run(main()) end = time.perf_counter() print("Elapsed:", end - start)