def faceva_delete_person(client: SoapClient, token: str, name: str, statistic: Statistic) -> bool: """Функция выполнения ws метода FaceVA:DeletePerson :param client: объект класса SoapClient для отправки и приема ws запросов; :param token: токен соединения; :param name: :param statistic: :return: флаг успешности операции """ logger = log.get_logger("scripts/ws/analytics") logger.info( "was called (client: SoapClient, login: str, password: str, name: str, statistic: Statistic)" ) logger.debug("faceva_delete_person(client_obj" + login + ", " + password + ", " + name + ")") data = pattern.faceva_delete_person(login, password, name) response_json = client.call_method2(data[2], data[0], data[1], True) logger.debug("response_json: " + str(response_json)) tools.check_keys_exist(response_json['result'][0], ['cmd', 'name'], "response_json['result'][0]", True, statistic) #tools.check_on_equal_key_values_in_dict(response_json["result"][0], ['cmd', 'name'], ['DeletePerson', name]) logger.info("ws method FaceVA:DeletePerson was executed successfully!") statistic.append_info(method + " выполнен успешно!", "WS МЕТОД") return True
def ptzserver_command_simple(client: SoapClient, key2: str, token: str, statistic: Statistic, stop: bool = False, left: int = 0, right: int = 0, up: int = 0, down: int = 0, zoom_in: int = 0, zoom_out: int = 0, query_all: bool = False, go_to_preset: int = 0, set_preset: int = 0, pan_to: int = -1, tilt_to: int = -1, home: bool = False) -> dict: """ :param client: :param key2: :param token: :param stop: :param left: :param right: :param up: :param down: :param zoom_in: :param zoom_out: :param query_all: :param go_to_preset: :param set_preset: :param pan_to: :param tilt_to: :param home: :return: """ logger = statistic.get_log().get_logger("scripts/ws/ptz") logger.info( "was called (client: SoapClient, key2: str, token: str, statistic: Statistic, stop: bool,\ left: int, right: int, up: int, down: int, zoom_in: int, zoom_out: int, query_all: bool,\ go_to_preset: int, set_preset: int, pan_to: int, tilt_to: int, home: bool)" ) logger.debug("params (client_obj, " + key2 + ", " + token + ", statistic_obj" + str(stop) + ", " + str(left) + ", " + str(right) + ", " + str(up) + ", " + str(down) + ", " + str(zoom_in) + ", " + str(zoom_out) + ", " + str(query_all) + ", " + str(go_to_preset) + ", " + str(set_preset) + ", " + str(pan_to) + ", " + str(tilt_to) + ", " + str(home) + ")") params, sysparams, method = pattern.ptzserver_command_simple( key2, token, stop, left, right, up, down, zoom_in, zoom_out, query_all, go_to_preset, set_preset, pan_to, tilt_to, home) response = client.call_method2(method, params, sysparams, [0]) logger.info("ws method ptzserver:Command was executed successfully!") statistic.append_info("ptzserver:Command выполнен успешно", "WS_МЕТОД") return response
def faceva_get_event_image(client: SoapClient, token: str, event: int, time: int, statistic: Statistic) -> dict: """Функция выполнения ws метода FaceVA:GetEventImage. :param client: объект класса SoapClient для отправки и приема ws запросов; :param token: токен соединения; :param event: номер события; :param time: время события (в unix формате); :param statistic: объект класса Statistic для ведения статистики ошибок и предупреждений :return: в случае успеха словарь ответа вида: { "img": "base64 code" } в случае ошибки словарь вида: { "result": "error" } """ logger = statistic.get_log().get_logger("scripts/ws/analytics") logger.info( "was called (client: SoapClient, token: str, event: int, time: int, statistic: Statistic)" ) logger.debug("params (client_obj" + token + ", " + str(event) + ", " + str(time) + ", stat_obf)") params, sysparams, method = pattern.faceva_get_event_image( token, event, time) response = client.call_method2(method, params, sysparams, [0]) statistic.append_info(method + " выполнен успешно!", "WS МЕТОД") return response['result'][0]
def open_json_file(path: str, statistic: Statistic) -> dict: """Открытие файла с содержимым в формате json. Функция считывает json из файла и преобразует в словарь. Если файл не существует - генерируется критическая ошибка. :param path: путь к файлу; :param statistic: объект класса Statistic. :return: сожержимое json файла в виде словаря. """ logger = statistic.get_log().get_logger("scripts/common/tools") logger.info("was called (path: str, statistic: Statistic)") logger.debug("with params (" + path + ", statistic_obj)") if not os.path.exists(path): statistic.append_error(path, "НЕ СУЩЕСТВУЕТ", True) with open(path, encoding='utf-8') as json_file: try: logger.info("open json file '" + path + "' was executed successfully") result = json.load(json_file) statistic.append_info( "Открытие файла '" + path + "' выполнено успешно...", "JSON_ФАЙЛ") return result except json.JSONDecodeError: logger.error("В файле '" + path + "' отсутствует корректная строка JSON!") statistic.append_error( "В файле '" + path + "' отсутствует корректная строка JSON!", "JSON_ФАЙЛ", True)
def _send_request(zmqclient: ZmqClient, xml_tree_full: Tree, message_id: str, timeout: float, statistic: Statistic) -> Tree: """Функция отправки сообщения и с возможностью переотправки. :param zmqclient: объект класса ZmqClient; :param xml_tree_full: запрос дерево XML; :param message_id: id сообщения; :param timeout: время ожидания ответа; :param statistic: объект класса Statistic. :return: ответ в виде дерева XML. """ zmqclient.send_request(xml_tree_full) statistic.append_info("Отправка запроса с id: " + str(message_id), "ИНФО") send_count = 0 while True: list_xml_responses = _get_response(zmqclient, timeout) if list_xml_responses == -1: if send_count == 3: statistic.append_error("Повторная отправка сообщения '" + str(message_id) + "' завершилась с ошибкой!", "ZMQ_ОТВЕТ", True) break zmqclient.send_request(xml_tree_full) send_count += 1 statistic.append_warn("Попытка повторной отправки сообщеия '" + str(message_id), "ZMQ_ОТВЕТ") continue response_index = search_response_index_by_message_id(list_xml_responses, message_id, statistic) if response_index > -1: statistic.append_info("Получен ответ на запрос с id '" + str(message_id) + "'", "ИНФО") zmqclient.remove_response(message_id) return list_xml_responses[response_index] return -1
def replace_region_values_on_cam_json(json_detector: dict, region_name: str, new_region: dict, force: bool, statistic: Statistic) -> dict: """Замена зоны по ключам (только существующие ключи). :param json_detector: json с секцией детектора; :param region_name: имя зоны; :param new_region: словарь с новым регионом; :param force: вставить принудительно настройку, если ее нет в json; :param statistic: объект класса Statistic. :return: json с измененной секцией детектора в зоне """ logger = statistic.get_log().get_logger("scripts/common/graph") logger.info("was called (json_detector: dict, region_name: str, new_region: dict, statistic: Statistic") logger.debug("with params (" + str(json_detector) + ", " + region_name + ", " + str(new_region) + ")") detector_name = get_plugin_type(json_detector, statistic) data = get_region_from_detector_json(json_detector, region_name, statistic) index_region = data[0] region = data[1] if index_region == -1: statistic.append_error(region_name, "НЕТ ЗОНЫ") return {} region_json = json_detector[detector_name]['detection_regions']['square']['_value'][index_region] for first_lvl_key in new_region.keys(): if tools.check_keys_exist(region, [first_lvl_key], region_name, False, statistic) is False: if force: region_json[first_lvl_key] = new_region[first_lvl_key] txt_msg = first_lvl_key + " в зоне '" + region_name + " выполнена успешно!" logger.info(txt_msg) statistic.append_success(txt_msg, "ПРИНУДИТЕЛЬНАЯ ВСТАВКА КЛЮЧА В ЗОНЕ") continue # если данный ключ является отрисовкой зоны _points, то содержимое меняем # немного по другому if first_lvl_key == '_points': region_json['_points'] = new_region['_points'] txt_msg = "_ points в зоне " + region_name + " выполнена успешно!" logger.info(txt_msg) statistic.append_info(txt_msg, "ЗАМЕНА КЛЮЧЕЙ В ЗОНЕ") continue # для остальных ключей делаем замену в _value if tools.check_keys_exist(region[first_lvl_key], ['_value'], region_name + "[" + str(index_region) + "]", False, statistic) is False: continue if tools.check_keys_exist(new_region[first_lvl_key], ['_value'], first_lvl_key + " в новом регионе!", False, statistic) is False: continue region_json[first_lvl_key]['_value'] = new_region[first_lvl_key]['_value'] txt_msg = first_lvl_key + "[_value] в зоне '" + region_name + " выполнена успешно!" logger.info(txt_msg) statistic.append_success(txt_msg, "ЗАМЕНА КЛЮЧА В ЗОНЕ") return json_detector
def get_cam_json(path_to_db: str, key1: str, key2: str, key3: str, statistic: Statistic) -> dict: """Получение json графа (камеры) из БД. Делает SELECT запрос к БД на получение json-ов всех камер и профилей, а затем осуществляется поиск нужной камеры. :param path_to_db: путь к файлу БД; :param key1: имя сервера; :param key2: имя камеры; :param key3: профиль камеры; :param statistic: объект класса Statistic. :return: json в виде словаря. """ logger = statistic.get_log().get_logger("scripts/common/db") logger.info( "was called path_to_db: str, key1: str, key2: str, key3: str, statistic: Statistic)" ) logger.debug("with params (" + path_to_db + ", " + key1 + ", " + key2 + ", " + key3 + ")") if not os.path.exists(path_to_db): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.2) conn = sqlite3.connect(path_to_db) cursor = conn.cursor() db_setname = key1 + "_" + key2 + "_" + key3 sql_cmd = 'SELECT setvalue FROM setting WHERE settypeid = ? AND setname = ?' cursor.execute(sql_cmd, [1, db_setname]) json_cam = cursor.fetchall() conn.commit() conn.close() if not json_cam: statistic.append_error("Камера '" + db_setname + "' отсутствует!", "БД") return {} logger.info("db select json by '" + db_setname + "' cam was executed successfully!") statistic.append_info( "Получение json из БД камеры '" + db_setname + "' выполнено успешно!", "БД") # в некоторых плагинах есть сочетания слешей вида: \/, которое нельзя никак заменять. # При десериализации по умолчанию символ \ пропадает, как служебный. # Поэтому перед десериализацией необходимо добавить два слеша, чтобы было так (\\/). # Однако почему то в таком случае после десериализации оно так и останется (\\/), а не (\/). # То есть потом при сериализации этот момент нужно учесть и заменить на \/. replaced_json_cam = json_cam[0][0].replace("\\/", "\\\\/") return json.loads(replaced_json_cam, parse_float=json_float_parser) except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def insert_graphs_to_db(ws_client: SoapClient, token: str, path_to_db: str, json_: dict, key1: str, key3: str, count: int, statistic: Statistic) -> tuple: """Добавление в БД указанного количества графов c указанным json. Соблюдается уникальность key2 и id54 в БД. :param ws_client: объект клиента класса SoapClient; :param token: логин пользователя для ws метода; :param path_to_db: путь к БД; :param json_: json графа (камеры); :param key1: имя сервера; :param key3: профиль key3; :param count: количество графов для добавления в БД; :param statistic: объект класса Statistic. :return: кортеж key2 добавленных камер. """ logger = statistic.get_log().get_logger("scripts/common/graph") logger.info("was called (client: SoapClient, login: str, password: str, path_to_db: str, json_: dict, key1: str," + "key3: str, count: int, statistic: Statistic)") logger.info("call func db.get_lists_id54_and_key2(path_to_db)") logger.debug("params (" + path_to_db + ")") list_key2 = list(db.get_cams_names(path_to_db, key1, statistic)) list_id54 = list(db.get_cams_id(path_to_db, statistic)) logger.debug("list_key2: " + str(list_key2)) logger.debug("list_id54: " + str(list_id54)) list_new_key2: list = [] for graph in range(count): free_id54 = get_free_id54(tuple(list_id54)) free_key2 = get_free_key2(tuple(list_key2), free_id54) logger.debug("free_id54: " + str(free_id54)) logger.debug("free_key2: " + str(free_key2)) list_id54.append(free_id54) list_key2.append(free_key2) list_new_key2.append(free_key2) set_key2(json_, free_key2, statistic) set_id54(json_, free_id54, statistic) setid = db.insert_new_cam(path_to_db, key1, free_key2, key3, json_, statistic) logger.info("Вставка камеры '" + free_key2 + "' в БД выполена успешно!") statistic.append_info("Вставка камеры '" + free_key2 + "' в БД выполена успешно!", "ИНФО") ws_video_server.reload_graph(ws_client, token, setid, statistic) logger.info("Перезагрузка графа в процессе по камере " + free_key2 + " выполнена успешно!") statistic.append_info("Перезагрузка графа в процессе по камере " + free_key2 + " выполнена успешно!", "ИНФО") return tuple(list_new_key2)
def get_down_servers(client: SoapClient, token: str, direct_access: int, statistic: Statistic) -> dict: """WS метод listener_pinger_get_down_servers с проверками существования ключей и типов их значений. :param client: объект клиента; :param token: токен авторизации; :param direct_access: параметр ws метода; :param statistic: объект класса Statistic. :return: response["result"][0]["data"]["string"] """ logger = statistic.get_log().get_logger("scripts/ws/listener_pinger") logger.info( "was called (client: SoapClient, token: str, direct_access: int, statistic: Statistic)" ) logger.debug("with params (client_obj, " + token + ", " + str(direct_access) + ", stat_obj)") params, sysparams, method = pattern.listener_pinger_get_down_servers( token, direct_access) response = client.call_method2(method, params, sysparams, [0]) tools.check_types(["response['result'][0]"], [response["result"][0]], [dict], statistic) tools.check_keys_exist(response["result"][0], ['data', 'hash'], 'response["result"][0]', False, statistic) tools.check_types( ['data', 'hash'], [response["result"][0]["data"], response["result"][0]["hash"]], [dict, str], statistic) tools.check_keys_exist(response["result"][0]["data"], ['string'], 'response["result"][0]["data"]', False, statistic) tools.check_types(["response['result'][0]['data']['string']"], [response["result"][0]["data"]["string"]], [dict], statistic) string = response["result"][0]["data"]["string"] tools_lp.listener_pinger_keys_verifier(string, statistic) for down_server in string["down_servers"]: for key in down_server: tools_lp.listener_pinger_keys_verifier(down_server[key], statistic) logger.info("ws '" + method + "' выполнен успешно!") statistic.append_info(method + "' выполнен успешно!", "WS_МЕТОД") return response["result"][0]["data"]["string"]
def write_to_file(path: str, content: str, statistic: Statistic) -> None: """Функция записи в файл. :param path: путь к файлу; :param content: содержимое для записи; :param statistic: объект класса Statistic. """ logger = statistic.get_log().get_logger("scripts/common/tools") logger.info("was called (path: str, content: str)") logger.debug("with params (" + path + ", " + content + ")") with open(path, 'w') as txt_file: txt_file.write(content) logger.info("write content to file '" + path + "' was executed successfully!") statistic.append_info( "Запись в файл '" + path + "' выполнена успешно!", "ИНФО")
def ptzserver_list_profiles(client: SoapClient, token: str, statistic: Statistic) -> list: logger = statistic.get_log().get_logger("scripts/ws/ptz") logger.info( "was called (client: SoapClient, token: str, statistic: Statistic)") logger.debug("with params (client_obj, " + token + ", stat_obj)") params, sysparams, method = pattern.ptzserver_list_profiles(token) response = client.call_method2(method, params, sysparams, [0]) logger.info("ws method " + method + " was executed successfully!") statistic.append_info(method + " выполнен успешно!", "WS_МЕТОД") if not response["result"] or response["result"] == [{}]: statistic.append_error("Список PTZ камер пуст!", "НЕТ PTZ КАМЕР") return [] return response["result"]
def faceva_get_data_base(client: SoapClient, token: str, statistic: Statistic) -> tuple: """Функция выполнеия ws метода FaceVA:GetDataBase :param client: объект класса SoapClient для отправки и приема ws запросов; :param token: токен соединения; :param statistic: объект класса Statistic для ведения статистики ошибок и предупреждений. :return: список персон, который приходит в ответе в ключе persons вида: [ { "id": 26617065162932227, "name": Иванов Иван Иванович, ["pacs": 1], ["category": "category"], ["department": "department"], ["comment": "comment"], ["information": "information"] } ] """ logger = statistic.get_log().get_logger("scripts/ws/analytics") logger.info("was called(client, login, password)") logger.debug("with params (client_obj, " + token + ", stat_obj)") params, sysparams, method = pattern.faceva_get_data_base(token) response_json = client.call_method2(method, params, sysparams, [0]) result = response_json["result"][0] tools.check_keys_exist(result, ['persons'], "result", True, statistic) persons = result["persons"] tools.check_types(["persons"], [persons], [list], statistic) if not persons: statistic.append_warn("data base persons", "EMPTY") for person in persons: tools.check_keys_exist(person, ["id", "name"], 'person', True, statistic) logger.info("ws method FaceVA:GetDataBase was executed successfully!") statistic.append_info(method + " выполнен успешно!", "WS МЕТОД") return tuple(persons)
def faceva_update_person(client: SoapClient, token: str, id_: int, pacs_id: int, name: str, category: str, comment: str, information: str, department: str, faces: Tuple[dict], delete_faces: Tuple[dict], statistic: Statistic) -> str: """Функция выполнения ws метода FaceVA:UpdatePerson. :param client: объект класса SoapClient для отправки и приема ws запросов; :param token: токен соединения; :param id_: идентификатор персоны в БД; :param pacs_id: идентификатор персоны в БД для СКД; :param name: ФИО персоны; :param category: категория; :param comment: комментарий; :param information: информация; :param department: отдел; :param faces: список фото лиц для добавления; :param delete_faces: список фото для удаления; :param statistic: объект класса Statistic для ведения статистики ошибок и предупреждений. :return: идентификатор персоны в базе. """ logger = statistic.get_log().get_logger("scripts/ws/analytics") logger.info( "was called faceva_update_person(client: SoapClient, login: str, id_: int, pacs_id: int,\ name: str, category: str, comment: str, information: str, department: str, faces: List[dict], \ delete_faces: List[dict])") logger.debug("faceva_update_person(client_obj" + token + ", " + str(id_) + ", " + str(pacs_id) + ", " + name + ", " + category + ", " + comment + ", " + information + ", " + department + ", " + ", " + str(faces) + ", " + str(delete_faces) + ")") params, sysparams, method = pattern.faceva_update_person( token, id_, pacs_id, name, category, comment, information, department, faces, delete_faces) response_json = client.call_method2(method, params, sysparams, [0]) person = response_json['result'][0] key_names = [ "id", "pacs", "name", "category", "comment", "information", "department", "result", "faces" ] tools.check_keys_exist(person, key_names, "['result'][0]", True, statistic) key_names.remove("result") key_names.remove("faces") key_values = [ person["id"], person["pacs"], person["name"], person["category"], person["comment"], person["information"], person["department"] ] key_need_values = [ id_, str(pacs_id), name, category, comment, information, department ] operations = ["==", "==", "==", "==", "==", "==", "=="] if id_ == -1: key_names.pop(0) key_values.pop(0) key_need_values.pop(0) operations.pop(0) tools.check_values(key_names, key_values, key_need_values, operations, statistic) tools.check_types(["faces"], [person["faces"]], [list], statistic) if not person['faces'] and faces: statistic.append_error("Список faces", "НЕТ_ЛИЦ", True) for index, face in enumerate(person["faces"]): tools.check_keys_exist(face, ["result"], "face", True, statistic) if face["result"] == "error": tools.check_keys_exist(face, ["reason"], "face", True, statistic) statistic.append_error("причина: " + face["reason"], "ПЛОХОЕ_ФОТО", False) logger.info("ws method FaceVA:UpdatePerson was executed successfully!") statistic.append_info(method + " выполнен успешно!", "WS МЕТОД") return person["id"]
def compare_down_servers(string: dict, template_string: dict, main_server_ip: str, statistic: Statistic) -> bool: """Функция проверки эквивалентности "нижних" серверов :param string: строка ответа; :param template_string: эталонная строка; :param main_server_ip: ip главного сервера; :param statistic: объект класса Statistic. :return: флаг корректности. """ is_correct = True if string == template_string: return is_correct if compare_local_servers(string, template_string, main_server_ip, statistic) is False: statistic.append_info( "Локальный сервер некорректен в ответе 'get_down' на сервере " + main_server_ip, "СРАВНЕНИЕ") is_correct = False if string["down_servers"] == template_string["down_servers"]: return is_correct if not string["down_servers"] and template_string["down_servers"]: statistic.append_error("Сервер " + main_server_ip + "!", "НЕТ НИЖНИХ СЕРВЕРОВ") is_correct = False if not template_string["down_servers"] and string["down_servers"]: statistic.append_warn("Сервер " + main_server_ip + "!", "ЕСТЬ НИЖНИЕ СЕРВЕРА") #is_correct = False # проход по шаблону и поиск отличий down_servers_names: list = get_down_servers_names(string["down_servers"]) for template_down_server in template_string["down_servers"]: template_down_server_name: str = list(template_down_server.keys())[0] statistic.append_info( "Сравнение нижнего сервера " + template_down_server_name + " с шаблоном...", "ИНФО") if template_down_server_name not in down_servers_names: statistic.append_error( template_down_server_name + " на сервере" + main_server_ip + "!", "НЕТ НИЖНЕГО СЕРВЕРА") is_correct = False continue down_server_index = down_servers_names.index(template_down_server_name) down_server_string = string["down_servers"][down_server_index][ template_down_server_name] down_server_template_string = template_down_server[ template_down_server_name] if compare_local_servers( down_server_string, down_server_template_string, template_down_server_name, statistic) is False: statistic.append_error( "Нижний сервер " + template_down_server_name + " не корректен!", "СРАВНЕНИЕ") is_correct = False continue # поиск отсутвующих нижних серверов в шаблоне # тобиш, которые есть по факту, но нет в шаблоне template_down_servers_names: list = get_down_servers_names( template_string["down_servers"]) for down_server_name in down_servers_names: if template_down_servers_names.count(down_server_name) == 0: statistic.append_warn( down_server_name + " на сервере " + main_server_ip + " в ШАБЛОНЕ!", "НЕТ НИЖНЕГО СЕРВЕРА") return is_correct
def faceva_get_faces(client: SoapClient, token: str, from_: int, statistic: Statistic) -> Tuple[dict]: """Функция выполнения ws метода FaceVA:GetFaces. :param client: объект класса SoapClient для отправки и приема ws запросов; :param token: токен соединения; :param from_: начиная с какого id прислать события :param statistic: объект класса Statistic для ведения статистики ошибок и предупреждений :return: список словарей с событиями вида: [ { "event": 154743, "camera": 1955154395, "person": "26617065381036041", // если не пустой, значит это СВОЙ, иначе просто обнаруженное лицо. "score": 0.939386, "time": 1587380094085000, "img": "base64" }, ... ... ] """ logger = statistic.get_log().get_logger("scripts/ws/analytics") logger.info( "was called (client: SoapClient, token: str, from_: int, statistic: Statistic)" ) logger.debug("params (client_obj" + token + ", " + str(from_) + ", stat_obf)") params, sysparams, method = pattern.faceva_get_faces(token, from_) response: dict = client.call_method2(method, params, sysparams, [0]) for index, event in enumerate(response['result']): # пришлось написать это условие, так как может быть ситуация: result: [{}], # это означает, что событий нет. if not event and len(response['result']) == 1: break key_names = ['event', 'camera', 'rect', 'score', 'time', 'img'] tools.check_keys_exist(event, key_names, "result[" + str(index) + "]", True, statistic) key_values = [ event['event'], event['camera'], event['rect'], event['score'], event['time'], event['img'] ] tools.check_types(key_names, key_values, [int, int, dict, float, int, str], statistic) key_names = ['x', 'y', 'w', 'h'] tools.check_keys_exist(event['rect'], key_names, "result[" + str(index) + "]['rect']", True, statistic) key_values = [ event['rect']['x'], event['rect']['y'], event['rect']['w'], event['rect']['h'] ] tools.check_types(key_names, key_values, [int, int, int, int], statistic) statistic.append_info(method + " выполнен успешно!", "WS МЕТОД") return tuple(response['result'])
def update_cam_json(db_path: str, key1: str, key2: str, key3: str, cam_json: dict, statistic: Statistic) -> int: """Изменение json указанной камеры в БД. :param db_path: путь к БД; :param key1: имя сервера; :param key2: имя камеры; :param key3: профиль камеры; :param cam_json: json (граф) камеры; :param statistic: объект класса Statistic. :return: код ошибки: 0 - все ок. """ logger = statistic.get_log().get_logger("scripts/common/db") logger.info( "was called (db_path: str, key1: str, key2: str, key3: str, cam_json: dict, statistic: Statistic)" ) logger.debug("with params (" + db_path + ", " + key1 + ", " + key2 + ", " + key3 + ", " + str(cam_json) + ", stat_obj)") if not os.path.exists(db_path): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.2) conn = sqlite3.connect(db_path) cursor = conn.cursor() db_setname = key1 + "_" + key2 + "_" + key3 db_setvalue = json.dumps(cam_json, indent="\t", ensure_ascii=False) # Учитывается момент с \\/ и заменяется на \/. db_setvalue = db_setvalue.replace("\\\\/", "\\/") sql_cmd = "SELECT setid FROM setting WHERE settypeid = ? AND setname = ?" cursor.execute(sql_cmd, [1, db_setname]) db_setid = cursor.fetchall()[0][0] time.sleep(0.2) sql_cmd = "SELECT sethash FROM setting WHERE setid = ?" cursor.execute(sql_cmd, [str(db_setid)]) db_sethash = cursor.fetchall()[0][0] obj_md5_hash = hashlib.md5(db_setvalue.encode('utf-8')) db_sethash_new = obj_md5_hash.hexdigest() if db_sethash == db_sethash_new: conn.close() logger.info("cam '" + key2 + "' on server '" + key1 + "' already has the same json!") statistic.append_info( "Камера '" + db_setname + "' уже имеет такой json!", "БД") return 0 time.sleep(0.2) sql_cmd = "UPDATE setting SET setvalue = ?, sethash = ? WHERE setid = ?" cursor.execute(sql_cmd, [db_setvalue, db_sethash_new, str(db_setid)]) conn.commit() conn.close() logger.info("db update json for '" + key2 + "' cam was executed successfully") statistic.append_info( "Обновление json камеры '" + db_setname + "' выполнено успешно!", "БД") return 0 except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def get_coordinates(client: SoapClient, login: str, password: str, key2: str, statistic: Statistic) -> dict: """Функция для получения координат (использует ws метод ptzclient:Command). :param client: объект soap клиента; :param login: логин пользователя; :param password: пароль пользователя; :param key2: имя камеры; :param statistic: объект класса Statistic. :return: словарь с координатами (ключи pan и tilt). """ logger = statistic.get_log().get_logger("scripts/tools/ptz") logger.info( "was called (client: SoapClient, login: str, password: str, key2: str)" ) logger.debug("with params (client_obj, " + login + ", " + password + ", " + key2 + ")") logger.info("call ptzclient_command_simple()") statistic.append_info("получение старых координат...", "ИНФО") logger.info("getting old coordinates") query_all_result = ws.ptzclient_command_simple(client, key2, login, password, False, 0, 0, 0, 0, 0, 0, True, 0, 0, -1, -1, False) tools.check_types(["old_coordinates['result'][0]"], [query_all_result["result"][0]], [dict], statistic) is_old_coordinates = tools.check_keys_exist( query_all_result["result"][0], ["pan", "tilt", "timecoords"], 'old_coordinates["result"][0]', False, statistic) old_timecoords = 0 if is_old_coordinates: old_pan = query_all_result["result"][0]["pan"] old_tilt = query_all_result["result"][0]["tilt"] old_timecoords = query_all_result["result"][0]["timecoords"] logger.debug("old_pan: " + str(old_pan) + ", old_tilt: " + str(old_tilt) + ", old_timecoords: " + str(old_timecoords)) count_coordinates_missing = 0 while True: logger.info("call ptzclient_command_simple()") statistic.append_info("получение текуших координат...", "ИНФО") logger.info("getting current coordinates") current_coordinates = ws.ptzclient_command_simple( client, key2, login, password, False, 0, 0, 0, 0, 0, 0, True, 0, 0, -1, -1, False) tools.check_types(["current_coordinates['result'][0]"], [current_coordinates["result"][0]], [dict], statistic) is_current_coordinates = tools.check_keys_exist( current_coordinates["result"][0], ["pan", "tilt"], 'current_coordinates["result"][0]', False, statistic) if is_current_coordinates is False: count_coordinates_missing += 1 if count_coordinates_missing == 3: statistic.append_error( "Получение координат завершилось с ошибкой!", "НЕТ_КООРДИНАТ", False) break continue current_timecoords = current_coordinates["result"][0]["timecoords"] if is_old_coordinates and current_timecoords != old_timecoords or is_old_coordinates is False: current_pan = current_coordinates["result"][0]["pan"] current_tilt = current_coordinates["result"][0]["tilt"] logger.debug("current_pan: " + str(current_pan) + ", current_tilt: " + str(current_tilt)) return {"pan": current_pan, "tilt": current_tilt}
def go_to_coordinate(client: SoapClient, login: str, password: str, key2: str, ws_method: str, cmd: str, coordinate: int, statistic: Statistic, inaccuracy: int = 0) -> bool: """Функция перевода камеры в указанные координаты. :param client: объект soap клиентя :param login: логин пользователя :param password: пароль пользователя :param key2: имя камеры :param ws_method: через какой метод выполнять команду (ptzserver или ptzclient) :param cmd: команда :param coordinate: координаты :param statistic: объект класса Statistic :param inaccuracy точность :return: флаг успешности перехода """ logger = statistic.get_log().get_logger("scripts/tools/ptz") logger.info( "was called (client: SoapClient, login: str, password: str, key2: str, \ cmd: str, coordinate: int, inaccuracy: int = 0)") logger.debug("with params (client_obj, " + login + ", " + password + ", " + key2 + ", " + cmd + ", " + str(coordinate) + ", " + str(inaccuracy) + ")") pan_to = -1 tilt_to = -1 if cmd == "PanTo": pan_to = coordinate elif cmd == "TiltTo": tilt_to = coordinate else: statistic.append_error(cmd, "НЕВАЛИД_КОМАНДА_PTZ", True) if ws_method == "ptzclient": ws.ptzclient_command_simple(client, key2, login, password, False, 0, 0, 0, 0, 0, 0, False, 0, 0, pan_to, tilt_to, False) message = "ws 'ptzclient:Command[" + cmd + "=" + str( coordinate) + "]' отправлен..." elif ws_method == "ptzserver": ws.ptzserver_command_simple(client, key2, login, password, False, 0, 0, 0, 0, 0, 0, False, 0, 0, pan_to, tilt_to, False) message = "ws 'ptzserver:Command[" + cmd + "=" + str( coordinate) + "]' отправлен..." else: statistic.append_error(ws_method, "НЕВАЛИД_МЕТОД_PTZ", True) statistic.append_info(message, "ПЕРЕХОД В КООРДИНАТЫ") logger.info(message) time.sleep(1) coordinates = get_coordinates(client, login, password, key2, statistic) if cmd == "TiltTo": current_coordinate = coordinates["tilt"] else: current_coordinate = coordinates["pan"] if compare_coordinates(coordinate, current_coordinate, inaccuracy): statistic.append_info( cmd + " " + str(coordinate) + " выполнена успешно!", "УСПЕХ") logger.info(cmd + " " + str(coordinate) + " was executed successfully!") return True else: return False
def turn(client: SoapClient, login: str, password: str, key1: str, key2: str, key3: str, cmd: str, statistic: Statistic) -> bool: """Функция для поворота камеры в нужную сторону (right, left, up, down) с использованием нужного ws метода. либо ptzserver:command (key1 и key3 != ""), либо ptzclient:command (key1 и key3 == ""). :param client: объект soap клиентя :param login: логин пользователя :param password: пароль пользователя :param key1: имя сервера. Если нужно осуществить поворот с помощью ws метода ptzserver:command, то key1 должен быть обязательно заполнен (!= "") :param key2: имя камеры :param key3: профиль камеры. Если нужно осуществить поворот с помощью ws метода ptzserver:command, то key3 должен быть обязательно заполнен (!= "") :param cmd: направление поворота - right, left, up, down :param statistic: объект класса Statistic :return: флаг успешности поворота """ logger = statistic.get_log().get_logger("scripts/tools/ptz") logger.info( "was called (client: SoapClient, login: str, password: str, key1: str, key2: str, key3: str, cmd: str)" ) logger.debug("with params (client_obj, " + login + ", " + password + ", " + key1 + ", " + key2 + ", " + key3 + ", " + cmd + ")") left = 0 right = 0 up = 0 down = 0 if cmd == "left": left = 70 elif cmd == "right": right = 70 elif cmd == "up": up = 70 elif cmd == "down": down = 70 coordinates = get_coordinates(client, login, password, key2, statistic) if cmd == "up" or cmd == "down": current_coordinate = coordinates["tilt"] else: current_coordinate = coordinates["pan"] statistic.append_info("поворот " + cmd + "...", "ИНФО") logger.info("turning " + cmd) if key1 == "" and key3 == "": ws.ptzclient_command_simple(client, key2, login, password, False, left, right, up, down, 0, 0, False, 0, 0, -1, -1, False) statistic.append_info( "ws 'ptzclient:Command[" + cmd + "=70]' отправлен...", "ПОВОРОТ") logger.info("ws method 'ptzclient:Command[" + cmd + "=70]' was sent") ws.ptzclient_command_simple(client, key2, login, password, True, 0, 0, 0, 0, 0, 0, False, 0, 0, -1, -1, False) # отправка остановки statistic.append_info("ws 'ptzclient:Command[" + cmd + "=0]' отправлен...", "ОСТАНОВКА") logger.info("ws method 'ptzclient:Command[" + cmd + "=0]' was sent") old_coordinate = current_coordinate coordinates = get_coordinates(client, login, password, key2, statistic) if cmd == "up" or cmd == "down": current_coordinate = coordinates["tilt"] else: current_coordinate = coordinates["pan"] if compare_coordinates(old_coordinate, current_coordinate) is False: statistic.append_info("Поворот " + cmd + " успешно выполнен!", "ПОВОРОТ") logger.info("turning " + cmd + " was executed successfully!") return True else: return False