From 459347f2c47dbdd34d17ed0c1420ca4bcb28ece1 Mon Sep 17 00:00:00 2001 From: Leon Kushnir Date: Thu, 9 Jan 2025 19:13:51 +0200 Subject: [PATCH 1/2] Solution --- app/iot/devices.py | 38 ++++++++++++++--------------- app/iot/service.py | 26 ++++++++++---------- app/main.py | 61 +++++++++++++++++++++++++++------------------- 3 files changed, 68 insertions(+), 57 deletions(-) diff --git a/app/iot/devices.py b/app/iot/devices.py index 5ee5ba6a..82552011 100644 --- a/app/iot/devices.py +++ b/app/iot/devices.py @@ -1,4 +1,4 @@ -import time +import asyncio from .message import MessageType @@ -8,57 +8,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 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}]." ) - 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}]." ) - 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}]." ) - 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..44e6c83a 100644 --- a/app/iot/service.py +++ b/app/iot/service.py @@ -1,8 +1,9 @@ import random import string +import asyncio from typing import Protocol -from .message import Message, MessageType +from app.iot.message import Message, MessageType def generate_id(length: int = 8) -> str: @@ -12,13 +13,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 +27,23 @@ 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 program 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, device_id: str, msg_type: MessageType, data: str = "") -> None: + await self.devices[device_id].send_message(msg_type, data) diff --git a/app/main.py b/app/main.py index 33b8f3d3..a156841f 100644 --- a/app/main.py +++ b/app/main.py @@ -1,44 +1,55 @@ import time +import asyncio +from typing import Any, Awaitable from iot.devices import HueLightDevice, SmartSpeakerDevice, SmartToiletDevice -from iot.message import Message, MessageType +from iot.message import MessageType from iot.service import IOTService -def main() -> None: +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) + + +async def main() -> None: # create an IOT service service = IOTService() # create and register a few devices - 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) - - # 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"), - ] - - 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), - ] + hue_light, speaker, toilet = await asyncio.gather( + service.register_device(HueLightDevice()), + service.register_device(SmartSpeakerDevice()), + service.register_device(SmartToiletDevice()) + ) + + wake_up = run_sequence( + run_parallel( + service.send_msg(hue_light, MessageType.SWITCH_ON), + service.send_msg(speaker, MessageType.SWITCH_ON) + ), + service.send_msg(speaker, MessageType.PLAY_SONG, "Rick Astley - Never Gonna Give You Up") + ) + + sleep = run_sequence( + run_parallel( + service.send_msg(hue_light, MessageType.SWITCH_OFF), + service.send_msg(speaker, MessageType.SWITCH_OFF) + ), + service.send_msg(toilet, MessageType.FLUSH), + service.send_msg(toilet, MessageType.CLEAN) + ) # run the programs - service.run_program(wake_up_program) - service.run_program(sleep_program) + await service.run_program(run_parallel(wake_up, sleep)) if __name__ == "__main__": start = time.perf_counter() - main() + asyncio.run(main()) end = time.perf_counter() print("Elapsed:", end - start) From 6b51f5683fc879cc201dc6e05655e76811e6697e Mon Sep 17 00:00:00 2001 From: Leon Kushnir Date: Thu, 9 Jan 2025 22:38:54 +0200 Subject: [PATCH 2/2] . --- app/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/main.py b/app/main.py index a156841f..23fea908 100644 --- a/app/main.py +++ b/app/main.py @@ -43,7 +43,7 @@ async def main() -> None: service.send_msg(toilet, MessageType.CLEAN) ) - # run the programs + # run the programs. await service.run_program(run_parallel(wake_up, sleep))