""" Reolink Camera API """ import requests import datetime import json import logging _LOGGER = logging.getLogger(__name__) class ReolinkApi(object): def __init__(self, ip, channel): self._url = "http://" + ip + "/cgi-bin/api.cgi" self._ip = ip self._channel = channel self._token = None self._motion_state = False self._last_motion = 0 self._device_info = None self._motion_state = None self._ftp_state = None self._email_state = None self._ir_state = None self._rtspport = None self._rtmpport = None self._ptzpresets = dict() def status(self): if self._token is None: return param_channel = {"channel": self._channel} body = [{"cmd": "GetDevInfo", "action":1, "param": param_channel}, {"cmd": "GetNetPort", "action": 1, "param": param_channel}, {"cmd": "GetFtp", "action": 1, "param": param_channel}, {"cmd": "GetEmail", "action": 1, "param": param_channel}, {"cmd": "GetIrLights", "action": 1, "param": param_channel}, {"cmd": "GetPtzPreset", "action": 1, "param": param_channel}] param = {"token": self._token} response = self.send(body, param) try: json_data = json.loads(response.text) except: _LOGGER.error(f"Error translating response to json") return for data in json_data: try: if data["cmd"] == "GetDevInfo": self._device_info = data elif data["cmd"] == "GetNetPort": self._netport_settings = data self._rtspport = data["value"]["NetPort"]["rtspPort"] self._rtmpport = data["value"]["NetPort"]["rtmpPort"] elif data["cmd"] == "GetFtp": self._ftp_settings = data if (data["value"]["Ftp"]["schedule"]["enable"] == 1): self._ftp_state = True else: self._ftp_state = False elif data["cmd"] == "GetEmail": self._email_settings = data if (data["value"]["Email"]["schedule"]["enable"] == 1): self._email_state = True else: self._email_state = False elif data["cmd"] == "GetIrLights": self._ir_settings = data if (data["value"]["IrLights"]["state"] == "Auto"): self._ir_state = True else: self._ir_state = False elif data["cmd"] == "GetPtzPreset": self._ptzpresets_settings = data for preset in data["value"]["PtzPreset"]: if int(preset["enable"]) == 1: preset_name = preset["name"] preset_id = int(preset["id"]) self._ptzpresets[preset_name] = preset_id _LOGGER.debug(f"Got preset {preset_name} with ID {preset_id}") else: _LOGGER.debug(f"Preset is not enabled: {preset}") except: continue @property def motion_state(self): body = [{"cmd": "GetMdState", "action": 0, "param":{"channel":self._channel}}] param = {"token": self._token} response = self.send(body, param) try: json_data = json.loads(response.text) if json_data is None: _LOGGER.error(f"Unable to get Motion detection state at IP {self._ip}") self._motion_state = False return self._motion_state if json_data[0]["value"]["state"] == 1: self._motion_state = True self._last_motion = datetime.datetime.now() else: self._motion_state = False except: self._motion_state = False return self._motion_state @property def still_image(self): response = self.send(None, f"?cmd=Snap&channel={self._channel}&token={self._token}", stream=True) response.raw.decode_content = True return response.raw @property def snapshot(self): response = self.send(None, f"?cmd=Snap&channel={self._channel}&token={self._token}", stream=False) return response.content @property def ftp_state(self): return self._ftp_state @property def email_state(self): return self._email_state @property def ir_state(self): return self._ir_state @property def rtmpport(self): return self._rtmpport @property def rtspport(self): return self._rtspport @property def last_motion(self): return self._last_motion @property def ptzpresets(self): return self._ptzpresets def login(self, username, password): body = [{"cmd": "Login", "action": 0, "param": {"User": {"userName": username, "password": password}}}] param = {"cmd": "Login", "token": "null"} response = self.send(body, param) try: json_data = json.loads(response.text) except: _LOGGER.error(f"Error translating login response to json") return if json_data is not None: if json_data[0]["code"] == 0: self._token = json_data[0]["value"]["Token"]["name"] _LOGGER.info(f"Reolink camera logged in at IP {self._ip}") else: _LOGGER.error(f"Failed to login at IP {self._ip}. No token available") else: _LOGGER.error(f"Failed to login at IP {self._ip}. Connection error.") def logout(self): body = [{"cmd":"Logout","action":0,"param":{}}] param = {"cmd": "Logout", "token": self._token} self.send(body, param) def set_ftp(self, enabled): self.status() if not self._ftp_settings: _LOGGER.error("Error while fetching current FTP settings") return if enabled == True: newValue = 1 else: newValue = 0 body = [{"cmd":"SetFtp","action":0,"param": self._ftp_settings["value"] }] body[0]["param"]["Ftp"]["schedule"]["enable"] = newValue response = self.send(body, {"cmd": "SetFtp", "token": self._token} ) try: json_data = json.loads(response.text) if json_data[0]["value"]["rspCode"] == 200: return True else: return False except: _LOGGER.error(f"Error translating FTP response to json") return False def set_email(self, enabled): self.status() if not self._email_settings: _LOGGER.error("Error while fetching current email settings") return if enabled == True: newValue = 1 else: newValue = 0 body = [{"cmd":"SetEmail","action":0,"param": self._email_settings["value"] }] body[0]["param"]["Email"]["schedule"]["enable"] = newValue response = self.send(body, {"cmd": "SetEmail", "token": self._token} ) try: json_data = json.loads(response.text) if json_data[0]["value"]["rspCode"] == 200: return True else: return False except: _LOGGER.error(f"Error translating Email response to json") return False def set_ir_lights(self, enabled): self.status() if not self._ir_settings: _LOGGER.error("Error while fetching current IR light settings") return if enabled == True: newValue = "Auto" else: newValue = "Off" body = [{"cmd":"SetIrLights","action":0,"param": self._ir_settings["value"] }] body[0]["param"]["IrLights"]["state"] = newValue response = self.send(body, {"cmd": "SetIrLights", "token": self._token} ) try: json_data = json.loads(response.text) if json_data[0]["value"]["rspCode"] == 200: return True else: return False except requests.exceptions.RequestException: _LOGGER.error(f"Error translating IR Lights response to json") return False def send(self, body, param, stream=False): try: if (self._token is None and (body is None or body[0]["cmd"] != "Login")): _LOGGER.info(f"Reolink camera at IP {self._ip} is not logged in") return if body is None: response = requests.get(self._url, params=param, stream=stream) else: response = requests.post(self._url, data=json.dumps(body), params=param) return response except Exception: _LOGGER.error(f"Exception while calling Reolink camera API at ip {self._ip}") return None