From 377c176f886ae0c701edf30dc6f4c8e75b16afef Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 9 Jan 2025 17:24:20 +0100 Subject: [PATCH] solution --- app/iot/devices.py | 37 +++++++++++++++++++------------------ app/iot/service.py | 26 +++++++++++++------------- app/main.py | 26 +++++++++++++++++++------- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/app/iot/devices.py b/app/iot/devices.py index 5ee5ba6a..180ad615 100644 --- a/app/iot/devices.py +++ b/app/iot/devices.py @@ -1,4 +1,5 @@ import time +from asyncio import sleep from .message import MessageType @@ -8,57 +9,57 @@ # 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 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 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}]." ) - time.sleep(TIME_TO_SLEEP) + await 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 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 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}]." ) - time.sleep(TIME_TO_SLEEP) + await 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 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 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}]." ) - time.sleep(TIME_TO_SLEEP) + await sleep(TIME_TO_SLEEP) print("Smart Toilet received message.") diff --git a/app/iot/service.py b/app/iot/service.py index f12b6021..ffbceee1 100644 --- a/app/iot/service.py +++ b/app/iot/service.py @@ -2,7 +2,7 @@ import string from typing import Protocol -from .message import Message, MessageType +from app.iot.message import MessageType, Message def generate_id(length: int = 8) -> str: @@ -12,13 +12,13 @@ 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) class Device(Protocol): - def connect(self) -> None: + 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 +26,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: + async 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..4f638d61 100644 --- a/app/main.py +++ b/app/main.py @@ -1,11 +1,13 @@ +import asyncio import time +from typing import Awaitable, Any 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,9 +15,9 @@ 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 = [ @@ -32,13 +34,23 @@ def main() -> None: ] # run the programs - service.run_program(wake_up_program) - service.run_program(sleep_program) + sequences = [service.run_program(wake_up_program)] + parallels = [service.run_program(sleep_program)] + + await run_sequence(*sequences) + await run_parallel(*parallels) + +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) if __name__ == "__main__": start = time.perf_counter() - main() + asyncio.run(main()) end = time.perf_counter() print("Elapsed:", end - start)