Напишіть протокол TemperatureSensor з використанням typing.Protocol та декоратора @runtime_checkable, який визначає контракт для датчиків температури: два методи —
- read_temperature() → float (повертає поточну температуру в градусах Цельсія)
- get_sensor_id() → str (повертає унікальний ідентифікатор датчика)
Створіть чотири класи, що відповідають цьому протоколу:
-
WeatherAPISensor
- Ідентифікатор: "WAS26-Odesa"
- Метод read_temperature() повинен отримувати поточну температуру в Одесі з відкритого API погоди
(наприклад, open-meteo.com, wttr.in або будь-якого безкоштовного сервісу, що не вимагає ключа).
Якщо запит не вдався — підняти виняток.
-
SimulatedSensor
- Приймає в конструкторі базову температуру (base: float) та максимальне відхилення (deviation: float).
- Повертає base + випадкове значення в діапазоні [-deviation, +deviation].
-
FakeAlways25
- Завжди повертає 25.0 °C
- Ідентифікатор: "Fake-25"
-
BrokenSensor
- read_temperature() завжди піднімає RuntimeError("Датчик зламаний!")
- get_sensor_id() повертає "BROKEN-999"
Напишіть функцію monitor_room(sensors: list[TemperatureSensor]) → None, яка для кожного датчика виводить:
[ідентифікатор] Температура: 23.4 °C
або (якщо сталася помилка):
[ідентифікатор] ПОМИЛКА: Датчик зламаний!
Додайте до списку 4 об’єкти:
sensors = [ WeatherAPISensor(), SimulatedSensor(base=21.5, deviation=3.0), FakeAlways25(), BrokenSensor() ]
Викличте monitor_room(sensors).
Додатково продемонструйте перевірку сумісності:
print(isinstance(RealDHT22(), TemperatureSensor)) # True print(isinstance({"temp": 22}, TemperatureSensor)) # False
Бажано:
- використовувати type hints
- обробляти помилки мережі в WeatherAPISensor (try-except)
- використовувати requests або urllib для запиту до API погоди
- не використовувати платні API, які вимагають ключ
Приклад можливого API (без ключа):