Coverage for jumpstarter_driver_energenie/driver.py: 73%
55 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:21 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:21 +0200
2import requests
3from collections.abc import AsyncGenerator
4from dataclasses import dataclass, field
6from jumpstarter_driver_power.driver import PowerInterface, PowerReading
8from jumpstarter.driver import Driver, export
11@dataclass(kw_only=True)
12class EnerGenie(PowerInterface, Driver):
13 """
14 driver for the EnerGenie Programmable surge protector with LAN interface.
16 This driver was tested on EG-PMS2-LAN device only but should be easy to support other devices.
17 """
19 host: str | None = field(default=None)
20 password: str | None = field(default="1")
21 slot: int = 1
23 def login(self):
24 """
25 Log in to the programmable power switch.
27 :return: True if login is successful, False otherwise.
28 """
29 login_url = f"{self.base_url}/login.html"
30 try:
31 response = requests.post(login_url, data={"pw": self.password}, timeout=10)
32 return response.status_code == 200
33 except (requests.exceptions.ConnectionError, requests.exceptions.Timeout,
34 requests.exceptions.RequestException) as e:
35 self.logger.error(f"Login failed: {str(e)}")
36 return False
38 def __post_init__(self):
39 if hasattr(super(), "__post_init__"):
40 super().__post_init__()
41 # Programmable power switch initialitzation. The EG-PMS2-LAN device has up to 4 slots.
42 if self.slot < 1 or self.slot > 4:
43 raise ValueError("Slot must be between 1 and 4")
44 if self.host is None:
45 raise ValueError("Host must be specified")
46 self.logger.debug(f"Using Host: {self.host}, Slot: {self.slot}")
47 self.base_url = f"http://{self.host}"
50 def set_switch(self, switch_number, state):
51 """
52 Set the state of a specific switch.
54 :param switch_number: The switch number (1, 2, etc.).
55 :param state: The state to set (1 for ON, 0 for OFF).
56 :return: True if the operation is successful, False otherwise.
57 """
58 if state not in [0, 1]:
59 self.logger.error(f"Invalid state: {state}")
60 return False
62 if self.login():
63 self.logger.debug("Login successful!")
64 else:
65 self.logger.debug("Login failed!")
66 return False
67 data = {f"cte{switch_number}": state}
68 try:
69 response = requests.post(self.base_url, data=data, timeout=10)
70 if response.status_code != 200:
71 self.logger.error(f"Set switch {switch_number} to {state} state failed!")
72 return False
73 except (requests.exceptions.ConnectionError, requests.exceptions.Timeout,
74 requests.exceptions.RequestException) as e:
75 self.logger.error(f"Set switch failed: {str(e)}")
76 return False
78 self.logger.debug(f"Set switch {switch_number} to {state} state")
80 return True
82 @export
83 def on(self) -> None:
84 self.set_switch(self.slot, 1)
86 @export
87 def off(self) -> None:
88 self.set_switch(self.slot, 0)
90 @export
91 def read(self) -> AsyncGenerator[PowerReading, None]:
92 raise NotImplementedError