diff --git a/app/iot/devices.py b/app/iot/devices.py index 5ee5ba6a..541324c5 100644 --- a/app/iot/devices.py +++ b/app/iot/devices.py @@ -1,4 +1,4 @@ -import time +import asyncio from .message import MessageType @@ -6,59 +6,75 @@ 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 asyncio.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 asyncio.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 asyncio.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 asyncio.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 asyncio.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 asyncio.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 asyncio.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 asyncio.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 asyncio.sleep(TIME_TO_SLEEP) print("Smart Toilet received message.") diff --git a/app/iot/service.py b/app/iot/service.py index f12b6021..5085a57b 100644 --- a/app/iot/service.py +++ b/app/iot/service.py @@ -1,6 +1,7 @@ import random import string from typing import Protocol +import asyncio from .message import Message, MessageType @@ -10,10 +11,12 @@ 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 + ... # Ellipsis - similar to "pass", but sometimes has + # different meaning def disconnect(self) -> None: ... @@ -26,24 +29,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) + tasks = [self.send_msg(msg) for msg in program] + await asyncio.gather(*tasks) 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..3e9534a2 100644 --- a/app/main.py +++ b/app/main.py @@ -1,11 +1,13 @@ +import asyncio import time +from typing import Any, Awaitable from iot.devices import HueLightDevice, SmartSpeakerDevice, SmartToiletDevice from iot.message import Message, MessageType from iot.service import IOTService -def main() -> None: +async def main() -> None: # create an IOT service service = IOTService() @@ -13,32 +15,50 @@ 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) + + tasks = [ + service.register_device(hue_light), + service.register_device(speaker), + service.register_device(toilet) + ] + + device_ids = await asyncio.gather(*tasks) + hue_light_id, speaker_id, toilet_id = device_ids # 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"), + async def run_sequence(*functions: Awaitable[Any]) -> None: + for function in functions: + await function + + async def run_parallel(*functions: Awaitable[Any]) -> None: + await asyncio.gather(*functions) + + parallel_functions = [ + service.send_msg(Message(hue_light_id, MessageType.SWITCH_ON)), + service.send_msg(Message(speaker_id, MessageType.SWITCH_ON)), + service.send_msg( + Message( + speaker_id, + MessageType.PLAY_SONG, + "Rick Astley - Never Gonna Give You Up" + ) + ), ] - sleep_program = [ - Message(hue_light_id, MessageType.SWITCH_OFF), - Message(speaker_id, MessageType.SWITCH_OFF), - Message(toilet_id, MessageType.FLUSH), - Message(toilet_id, MessageType.CLEAN), + sequential_functions = [ + service.send_msg(Message(hue_light_id, MessageType.SWITCH_OFF)), + service.send_msg(Message(speaker_id, MessageType.SWITCH_OFF)), + service.send_msg(Message(toilet_id, MessageType.FLUSH)), + service.send_msg(Message(toilet_id, MessageType.CLEAN)), ] - # run the programs - service.run_program(wake_up_program) - service.run_program(sleep_program) + await run_parallel(*parallel_functions) + await run_sequence(*sequential_functions) if __name__ == "__main__": start = time.perf_counter() - main() + asyncio.run(main()) end = time.perf_counter() print("Elapsed:", end - start)