|
| 1 | +from api.recording import RecordingAPIMixin |
| 2 | +from .device import DeviceAPIMixin |
| 3 | +from .display import DisplayAPIMixin |
| 4 | +from .network import NetworkAPIMixin |
| 5 | +from .system import SystemAPIMixin |
| 6 | +from .user import UserAPIMixin |
| 7 | +from resthandle import Request |
| 8 | + |
| 9 | + |
| 10 | +class APIHandler(SystemAPIMixin, |
| 11 | + NetworkAPIMixin, |
| 12 | + UserAPIMixin, |
| 13 | + DeviceAPIMixin, |
| 14 | + DisplayAPIMixin, |
| 15 | + RecordingAPIMixin): |
| 16 | + """ |
| 17 | + The APIHandler class is the backend part of the API, the actual API calls |
| 18 | + are implemented in Mixins. |
| 19 | + This handles communication directly with the camera. |
| 20 | + Current camera's tested: RLC-411WS |
| 21 | +
|
| 22 | + All Code will try to follow the PEP 8 standard as described here: https://www.python.org/dev/peps/pep-0008/ |
| 23 | + """ |
| 24 | + |
| 25 | + def __init__(self, ip: str, username: str, password: str, https=False, **kwargs): |
| 26 | + """ |
| 27 | + Initialise the Camera API Handler (maps api calls into python) |
| 28 | + :param ip: |
| 29 | + :param username: |
| 30 | + :param password: |
| 31 | + :param proxy: Add a proxy dict for requests to consume. |
| 32 | + eg: {"http":"socks5://[username]:[password]@[host]:[port], "https": ...} |
| 33 | + More information on proxies in requests: https://stackoverflow.com/a/15661226/9313679 |
| 34 | + """ |
| 35 | + scheme = 'https' if https else 'http' |
| 36 | + self.url = f"{scheme}://{ip}/cgi-bin/api.cgi" |
| 37 | + self.ip = ip |
| 38 | + self.token = None |
| 39 | + self.username = username |
| 40 | + self.password = password |
| 41 | + Request.proxies = kwargs.get("proxy") # Defaults to None if key isn't found |
| 42 | + |
| 43 | + def login(self) -> bool: |
| 44 | + """ |
| 45 | + Get login token |
| 46 | + Must be called first, before any other operation can be performed |
| 47 | + :return: bool |
| 48 | + """ |
| 49 | + try: |
| 50 | + body = [{"cmd": "Login", "action": 0, |
| 51 | + "param": {"User": {"userName": self.username, "password": self.password}}}] |
| 52 | + param = {"cmd": "Login", "token": "null"} |
| 53 | + response = Request.post(self.url, data=body, params=param) |
| 54 | + if response is not None: |
| 55 | + data = response.json()[0] |
| 56 | + code = data["code"] |
| 57 | + if int(code) == 0: |
| 58 | + self.token = data["value"]["Token"]["name"] |
| 59 | + print("Login success") |
| 60 | + return True |
| 61 | + print(self.token) |
| 62 | + return False |
| 63 | + else: |
| 64 | + print("Failed to login\nStatus Code:", response.status_code) |
| 65 | + return False |
| 66 | + except Exception as e: |
| 67 | + print("Error Login\n", e) |
| 68 | + raise |
| 69 | + |
| 70 | + def _execute_command(self, command, data, multi=False): |
| 71 | + """ |
| 72 | + Send a POST request to the IP camera with given data. |
| 73 | + :param command: name of the command to send |
| 74 | + :param data: object to send to the camera (send as json) |
| 75 | + :param multi: whether the given command name should be added to the |
| 76 | + url parameters of the request. Defaults to False. (Some multi-step |
| 77 | + commands seem to not have a single command name) |
| 78 | + :return: response JSON as python object |
| 79 | + """ |
| 80 | + params = {"token": self.token, 'cmd': command} |
| 81 | + if multi: |
| 82 | + del params['cmd'] |
| 83 | + try: |
| 84 | + if self.token is None: |
| 85 | + raise ValueError("Login first") |
| 86 | + response = Request.post(self.url, data=data, params=params) |
| 87 | + return response.json() |
| 88 | + except Exception as e: |
| 89 | + print(f"Command {command} failed: {e}") |
| 90 | + raise |
0 commit comments