generated from pavel.muhortov/template-bash
add additional headers to Connect.http()
This commit is contained in:
parent
db76bb8e0b
commit
699492f77f
|
@ -1,6 +1,8 @@
|
|||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0302,C0114,W0621
|
||||
|
||||
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
import urllib.request
|
||||
|
@ -18,6 +20,7 @@ from paramiko import SSHClient, AutoAddPolicy
|
|||
class Parse:
|
||||
"""Parser of configs, arguments, parameters.
|
||||
"""
|
||||
# pylint: disable=C0123
|
||||
def __init__(self, parameters, block: str = None) -> None:
|
||||
"""Object constructor.
|
||||
|
||||
|
@ -65,6 +68,7 @@ class Parse:
|
|||
"""
|
||||
self.data.update(dictionary)
|
||||
|
||||
# pylint: disable=C0206
|
||||
def expand(self, store: str = None) -> dict:
|
||||
"""Expand dictionary "key":"name.conf" to dictionary "key":{subkey: subval}.
|
||||
|
||||
|
@ -79,7 +83,7 @@ class Parse:
|
|||
config = store + sep + self.data[key]
|
||||
else:
|
||||
config = self.data[key]
|
||||
with open(config) as file:
|
||||
with open(config, encoding='UTF-8') as file:
|
||||
self.data[key] = Parse(file.read()).data
|
||||
return self.data
|
||||
|
||||
|
@ -106,7 +110,7 @@ class Parse:
|
|||
Returns:
|
||||
str: string as "var1=val1;\nvar2=val2;".
|
||||
"""
|
||||
with open(config) as file:
|
||||
with open(config, encoding='UTF-8') as file:
|
||||
raw = file.read()
|
||||
strs = ''
|
||||
for line in raw.splitlines():
|
||||
|
@ -130,7 +134,9 @@ class Parse:
|
|||
strings = cls.block(blockname, strings)
|
||||
for line in strings.replace('\n', ';').split(';'):
|
||||
if not line.lstrip().startswith('#') and "=" in line:
|
||||
dictionary[line.split('=')[0].strip()] = line.split('=')[1].strip().split(';')[0].strip()
|
||||
dictionary[line.split('=')[0].strip()] = (
|
||||
line.split('=')[1].strip().split(';')[0].strip()
|
||||
)
|
||||
return dictionary
|
||||
|
||||
@classmethod
|
||||
|
@ -171,66 +177,93 @@ class Parse:
|
|||
|
||||
|
||||
class Connect:
|
||||
# pylint: disable=W0105
|
||||
"""Set of connection methods (functions) for various protocols.
|
||||
"""
|
||||
@staticmethod
|
||||
# pylint: disable=W0102, W0718
|
||||
def http(
|
||||
url: str, method: str = 'GET',
|
||||
username: str = '', password: str = '', authtype: str = None,
|
||||
contenttype: str = 'text/plain', contentdata: str = ''
|
||||
) -> str:
|
||||
url: str,
|
||||
method: str = 'GET',
|
||||
username: str = '',
|
||||
password: str = '',
|
||||
authtype: (str, type(None)) = None,
|
||||
contenttype: str = 'text/plain',
|
||||
contentdata: (str, bytes) = '',
|
||||
headers: dict = {}
|
||||
) -> dict:
|
||||
"""Handling HTTP request.
|
||||
|
||||
Args:
|
||||
url (str): request url.
|
||||
url (str): Handling HTTP request.
|
||||
method (str, optional): HTTP request method. Defaults to 'GET'.
|
||||
username (str, optional): username for url authentication. Defaults to ''.
|
||||
password (str, optional): password for url authentication. Defaults to ''.
|
||||
authtype (str, optional): digest|basic authentication type. Defaults to None.
|
||||
authtype (str, None, optional): digest|basic authentication type. Defaults to None.
|
||||
contenttype (str, optional): 'Content-Type' header. Defaults to 'text/plain'.
|
||||
contentdata (str, optional): content data. Defaults to ''.
|
||||
contentdata (str, bytes, optional): content data. Defaults to ''.
|
||||
headers (dict, optional): additional headers. Defaults to {}.
|
||||
|
||||
Returns:
|
||||
str: HTTP response or 'ERROR'.
|
||||
dict: {'success':bool,'result':HTTP response or 'ERROR'}.
|
||||
"""
|
||||
if Do.args_valid(locals(), Connect.http.__annotations__):
|
||||
if contentdata != '':
|
||||
headers['Content-Type'] = contenttype
|
||||
if isinstance(contentdata, str):
|
||||
contentdata = bytes(contentdata.encode('utf-8'))
|
||||
|
||||
# Preparing authorization
|
||||
if authtype:
|
||||
pswd = urllib.request.HTTPPasswordMgrWithDefaultRealm()
|
||||
pswd.add_password(None, url, username, password)
|
||||
if authtype == 'basic':
|
||||
auth = urllib.request.HTTPBasicAuthHandler(pswd)
|
||||
if authtype == 'digest':
|
||||
auth = urllib.request.HTTPDigestAuthHandler(pswd)
|
||||
urllib.request.install_opener(urllib.request.build_opener(auth))
|
||||
# Preparing authorization
|
||||
if authtype:
|
||||
pswd = urllib.request.HTTPPasswordMgrWithDefaultRealm()
|
||||
pswd.add_password(None, url, username, password)
|
||||
if authtype == 'basic':
|
||||
auth = urllib.request.HTTPBasicAuthHandler(pswd)
|
||||
token = base64.b64encode((username + ':' + password).encode())
|
||||
headers['Authorization'] = 'Basic ' + token.decode('utf-8')
|
||||
if authtype == 'digest':
|
||||
auth = urllib.request.HTTPDigestAuthHandler(pswd)
|
||||
urllib.request.install_opener(urllib.request.build_opener(auth))
|
||||
|
||||
# Preparing request
|
||||
request = urllib.request.Request(url=url, data=bytes(contentdata.encode('utf-8')), method=method)
|
||||
request.add_header('Content-Type', contenttype)
|
||||
|
||||
# Response
|
||||
try:
|
||||
response = urllib.request.urlopen(request).read()
|
||||
logging.debug(
|
||||
msg=''
|
||||
+ '\n' + 'uri: ' + url
|
||||
+ '\n' + 'method: ' + method
|
||||
+ '\n' + 'username: ' + username
|
||||
+ '\n' + 'password: ' + password
|
||||
+ '\n' + 'authtype: ' + authtype
|
||||
+ '\n' + 'content-type: ' + contenttype
|
||||
+ '\n' + 'content-data: ' + contentdata
|
||||
# Preparing request
|
||||
request = urllib.request.Request(
|
||||
url=url,
|
||||
data=contentdata,
|
||||
method=method
|
||||
)
|
||||
if response.startswith(b'\xff\xd8'):
|
||||
return response
|
||||
else:
|
||||
return str(response.decode('utf-8'))
|
||||
except Exception as error:
|
||||
logging.debug(msg='\n' + 'error: ' + str(error))
|
||||
return 'ERROR'
|
||||
for key, val in headers.items():
|
||||
request.add_header(key, val)
|
||||
if len(contentdata) > 128:
|
||||
contentdata = contentdata[:64] + b' ... ' + contentdata[-64:]
|
||||
logging.debug(msg=''
|
||||
+ '\n' + 'uri: ' + url
|
||||
+ '\n' + 'method: ' + method
|
||||
+ '\n' + 'username: ' + username
|
||||
+ '\n' + 'password: ' + password
|
||||
+ '\n' + 'authtype: ' + str(authtype)
|
||||
+ '\n' + 'headers: ' + json.dumps(headers, indent=2)
|
||||
+ '\n' + 'content-data: ' + str(contentdata)
|
||||
)
|
||||
|
||||
# Response
|
||||
try:
|
||||
response = urllib.request.urlopen(request).read()
|
||||
if not response.startswith(b'\xff\xd8'):
|
||||
response = str(response.decode('utf-8'))
|
||||
return {"success": True, "result": response}
|
||||
except Exception as error:
|
||||
logging.debug(msg='\n' + 'error: ' + str(error))
|
||||
return {"success": False, "result": "ERROR"}
|
||||
|
||||
@staticmethod
|
||||
def ssh_commands(command: str, hostname: str, username: str, password: str, port: int = 22) -> str:
|
||||
# pylint: disable=W0718
|
||||
def ssh_commands(
|
||||
command: str,
|
||||
hostname: str,
|
||||
username: str,
|
||||
password: str,
|
||||
port: int = 22
|
||||
) -> str:
|
||||
"""Handling SSH command executing.
|
||||
|
||||
Args:
|
||||
|
@ -267,7 +300,15 @@ class Connect:
|
|||
return 'ERROR'
|
||||
|
||||
@staticmethod
|
||||
def ssh_put_file(src_file: str, dst_file: str, hostname: str, username: str, password: str, port: int = 22) -> str:
|
||||
# pylint: disable=W0718
|
||||
def ssh_put_file(
|
||||
src_file: str,
|
||||
dst_file: str,
|
||||
hostname: str,
|
||||
username: str,
|
||||
password: str,
|
||||
port: int = 22
|
||||
) -> str:
|
||||
"""Handling SFTP upload file.
|
||||
|
||||
Args:
|
||||
|
@ -346,7 +387,14 @@ class Connect:
|
|||
return 'ERROR'
|
||||
'''
|
||||
@staticmethod
|
||||
def ftp_put_file(src_file: str, dst_file: str, hostname: str, username: str, password: str) -> bool:
|
||||
# pylint: disable=W0718,C0116
|
||||
def ftp_put_file(
|
||||
src_file: str,
|
||||
dst_file: str,
|
||||
hostname: str,
|
||||
username: str,
|
||||
password: str
|
||||
) -> bool:
|
||||
dst_path = dst_file.split('/')[:-1]
|
||||
ftp = FTP(host=hostname)
|
||||
try:
|
||||
|
@ -397,7 +445,7 @@ class HikISAPI(Connect):
|
|||
authtype: str = 'digest',
|
||||
hostport: int = 80, protocol: str = 'http',
|
||||
channel: int = 101, videoid: int = 1
|
||||
) -> None:
|
||||
) -> None:
|
||||
"""Object constructor.
|
||||
|
||||
Args:
|
||||
|
@ -424,23 +472,28 @@ class HikISAPI(Connect):
|
|||
url: str, method: str = 'GET',
|
||||
contenttype: str = 'application/x-www-form-urlencoded',
|
||||
contentdata: str = ''
|
||||
) -> str:
|
||||
) -> str:
|
||||
"""Send request to camera.
|
||||
|
||||
Args:
|
||||
url (str): API path for request.
|
||||
method (str, optional): HTTP request method. Defaults to 'GET'.
|
||||
contenttype (str, optional): Content-Type header. Defaults to 'application/x-www-form-urlencoded'.
|
||||
contenttype (str, optional): Content-Type header.
|
||||
Defaults to 'application/x-www-form-urlencoded'.
|
||||
contentdata (str, optional): data for send with request. Defaults to ''.
|
||||
|
||||
Returns:
|
||||
str: HTTP response content.
|
||||
str: HTTP response content or 'ERROR'.
|
||||
"""
|
||||
return self.http(
|
||||
response = self.http(
|
||||
url=url, method=method,
|
||||
username=self._user, password=self._pswd, authtype=self._auth,
|
||||
contenttype=contenttype, contentdata=contentdata
|
||||
)
|
||||
)
|
||||
if response['success']:
|
||||
return response['result']
|
||||
else:
|
||||
return 'ERROR'
|
||||
|
||||
def capabilities(self) -> bool:
|
||||
"""Get camera capabilities.
|
||||
|
@ -451,7 +504,7 @@ class HikISAPI(Connect):
|
|||
url = (
|
||||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._viid) + "/capabilities"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.info(msg='\n' + response + '\n')
|
||||
|
@ -459,11 +512,16 @@ class HikISAPI(Connect):
|
|||
else:
|
||||
return False
|
||||
|
||||
def downloadjpeg(self, dst_file: str = path.splitext(__file__)[0] + '.jpeg', x: int = 1920, y: int = 1080) -> bool:
|
||||
def downloadjpeg(
|
||||
self,
|
||||
dst_file: str = path.splitext(__file__)[0] + '.jpeg',
|
||||
x: int = 1920,
|
||||
y: int = 1080
|
||||
) -> bool:
|
||||
"""Get static picture from camera.
|
||||
|
||||
Args:
|
||||
dst_file (str, optional): absolute path of picture to save. Defaults to scriptname+'.jpeg'.
|
||||
dst_file (str, optional): abs picture's path to save. Defaults to scriptname+'.jpeg'.
|
||||
x (int, optional): picture width. Defaults to 1920.
|
||||
y (int, optional): picture height. Defaults to 1080.
|
||||
|
||||
|
@ -475,7 +533,7 @@ class HikISAPI(Connect):
|
|||
+ "/Streaming/channels/" + str(self._viid)
|
||||
+ "/picture?snapShotImageType=JPEG&videoResolutionWidth="
|
||||
+ str(x) + "&videoResolutionHeight=" + str(y)
|
||||
)
|
||||
)
|
||||
with open(dst_file, "wb") as file:
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
|
@ -491,8 +549,10 @@ class HikISAPI(Connect):
|
|||
Returns:
|
||||
bool: True if successed. Printing a response with a logger at the INFO level.
|
||||
"""
|
||||
url = (self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._chan) + "/status")
|
||||
url = (
|
||||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._chan) + "/status"
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.info(msg='\n' + response + '\n')
|
||||
|
@ -509,7 +569,7 @@ class HikISAPI(Connect):
|
|||
url = (
|
||||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/System/reboot"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method="PUT")
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -531,7 +591,7 @@ class HikISAPI(Connect):
|
|||
+ "/PTZ/channels/" + str(self._viid)
|
||||
+ "/PTZControl?command=TILT_UP&speed=" + str(speed)
|
||||
+ "&mode=start"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -553,7 +613,7 @@ class HikISAPI(Connect):
|
|||
+ "/PTZ/channels/" + str(self._viid)
|
||||
+ "/PTZControl?command=TILT_DOWN&speed=" + str(speed)
|
||||
+ "&mode=start"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -575,7 +635,7 @@ class HikISAPI(Connect):
|
|||
+ "/PTZ/channels/" + str(self._viid)
|
||||
+ "/PTZControl?command=PAN_LEFT&speed=" + str(speed)
|
||||
+ "&mode=start"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -597,7 +657,7 @@ class HikISAPI(Connect):
|
|||
+ "/PTZ/channels/" + str(self._viid)
|
||||
+ "/PTZControl?command=PAN_RIGHT&speed=" + str(speed)
|
||||
+ "&mode=start"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -619,7 +679,7 @@ class HikISAPI(Connect):
|
|||
+ "/PTZ/channels/" + str(self._viid)
|
||||
+ "/PTZControl?command=ZOOM_OUT&speed=" + str(speed)
|
||||
+ "&mode=start"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -641,7 +701,7 @@ class HikISAPI(Connect):
|
|||
+ "/PTZ/channels/" + str(self._viid)
|
||||
+ "/PTZControl?command=ZOOM_IN&speed=" + str(speed)
|
||||
+ "&mode=start"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -665,7 +725,7 @@ class HikISAPI(Connect):
|
|||
+ "/PTZControl?command=GOTO_PRESET&presetNo=" + str(preset)
|
||||
+ "&speed=" + str(speed)
|
||||
+ "&mode=start"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -683,7 +743,7 @@ class HikISAPI(Connect):
|
|||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/PTZ/channels/" + str(self._viid)
|
||||
+ "/PTZControl?command=GOTO_PRESET&mode=stop"
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method='GET')
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -706,7 +766,7 @@ class HikISAPI(Connect):
|
|||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._chan)
|
||||
+ "/absolute"
|
||||
)
|
||||
)
|
||||
xml = ''.join(
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
+ '<PTZData><AbsoluteHigh>'
|
||||
|
@ -726,9 +786,12 @@ class HikISAPI(Connect):
|
|||
"""Set camera moving to direction until other signal or 180 seconds elapse.
|
||||
|
||||
Args:
|
||||
x (int, optional): acceleration of horizontal camera movement from -100 to 100. Defaults to 0.
|
||||
y (int, optional): acceleration of vertical camera movement from -100 to 100. Defaults to 0.
|
||||
z (int, optional): acceleration of zoom camera movement from -100 to 100. Defaults to 0.
|
||||
x (int, optional): acceleration of horizontal camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
y (int, optional): acceleration of vertical camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
z (int, optional): acceleration of zoom camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
|
||||
Returns:
|
||||
bool: True if successed.
|
||||
|
@ -737,7 +800,7 @@ class HikISAPI(Connect):
|
|||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._chan)
|
||||
+ "/continuous"
|
||||
)
|
||||
)
|
||||
xml = ''.join(
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
+ '<PTZData>'
|
||||
|
@ -745,7 +808,7 @@ class HikISAPI(Connect):
|
|||
+ '<tilt>' + str(y) + '</tilt>'
|
||||
+ '<zoom>' + str(z) + '</zoom>'
|
||||
+ '</PTZData>'
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml)
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -757,10 +820,14 @@ class HikISAPI(Connect):
|
|||
"""Set camera moving to direction until other signal or duration elapse.
|
||||
|
||||
Args:
|
||||
x (int, optional): acceleration of horizontal camera movement from -100 to 100. Defaults to 0.
|
||||
y (int, optional): acceleration of vertical camera movement from -100 to 100. Defaults to 0.
|
||||
z (int, optional): acceleration of zoom camera movement from -100 to 100. Defaults to 0.
|
||||
t (int, optional): duration in ms of acceleration from 0 to 180000. Defaults to 180000.
|
||||
x (int, optional): acceleration of horizontal camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
y (int, optional): acceleration of vertical camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
z (int, optional): acceleration of zoom camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
t (int, optional): duration in ms of acceleration from 0 to 180000.
|
||||
Defaults to 180000.
|
||||
|
||||
Returns:
|
||||
bool: True if successed.
|
||||
|
@ -769,7 +836,7 @@ class HikISAPI(Connect):
|
|||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._chan)
|
||||
+ "/momentary"
|
||||
)
|
||||
)
|
||||
xml = ''.join(
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
+ '<PTZData>'
|
||||
|
@ -778,7 +845,7 @@ class HikISAPI(Connect):
|
|||
+ '<zoom>' + str(z) + '</zoom>'
|
||||
+ '<Momentary><duration>' + str(t) + '</duration></Momentary>'
|
||||
+ '</PTZData>'
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml)
|
||||
if response != 'ERROR':
|
||||
sleep(t/1000)
|
||||
|
@ -791,10 +858,14 @@ class HikISAPI(Connect):
|
|||
"""Set camera moving to direction (polymorph abstraction).
|
||||
|
||||
Args:
|
||||
x (int, optional): acceleration of horizontal camera movement from -100 to 100. Defaults to 0.
|
||||
y (int, optional): acceleration of vertical camera movement from -100 to 100. Defaults to 0.
|
||||
z (int, optional): acceleration of zoom camera movement from -100 to 100. Defaults to 0.
|
||||
t (int, optional): duration in ms of acceleration from 0 to 180000. Defaults to 0.
|
||||
x (int, optional): acceleration of horizontal camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
y (int, optional): acceleration of vertical camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
z (int, optional): acceleration of zoom camera movement from -100 to 100.
|
||||
Defaults to 0.
|
||||
t (int, optional): duration in ms of acceleration from 0 to 180000.
|
||||
Defaults to 0.
|
||||
|
||||
Returns:
|
||||
bool: True if successed.
|
||||
|
@ -814,11 +885,11 @@ class HikISAPI(Connect):
|
|||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._chan)
|
||||
+ "/homeposition/goto"
|
||||
)
|
||||
)
|
||||
xml = ''.join(
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
+ '<PTZData></PTZData>'
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml)
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -836,11 +907,11 @@ class HikISAPI(Connect):
|
|||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/PTZCtrl/channels/" + str(self._chan)
|
||||
+ "/homeposition"
|
||||
)
|
||||
)
|
||||
xml = ''.join(
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
+ '<PTZData></PTZData>'
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml)
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -848,7 +919,13 @@ class HikISAPI(Connect):
|
|||
else:
|
||||
return False
|
||||
|
||||
def settextonosd(self, enabled: str = "true", x: int = 0, y: int = 0, message: str = "") -> bool:
|
||||
def settextonosd(
|
||||
self,
|
||||
enabled: str = "true",
|
||||
x: int = 0,
|
||||
y: int = 0,
|
||||
message: str = ""
|
||||
) -> bool:
|
||||
"""Set message as video overlay text.
|
||||
|
||||
Args:
|
||||
|
@ -866,7 +943,7 @@ class HikISAPI(Connect):
|
|||
self._prot + '://' + self._host + ':' + str(self._port)
|
||||
+ "/ISAPI/System/Video/inputs/channels/" + str(self._chan)
|
||||
+ "/overlays/text"
|
||||
)
|
||||
)
|
||||
xml = ''.join(
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
+ '<TextOverlayList version="1.0" xmlns="http://www.hikvision.com/ver10/XMLSchema">'
|
||||
|
@ -878,7 +955,7 @@ class HikISAPI(Connect):
|
|||
+ '<displayText>' + message + '</displayText>'
|
||||
+ '</TextOverlay>'
|
||||
+ '</TextOverlayList>'
|
||||
)
|
||||
)
|
||||
response = self.__call(url=url, method="PUT", contenttype="text/xml", contentdata=xml)
|
||||
if response != 'ERROR':
|
||||
logging.debug(msg='\n' + response + '\n')
|
||||
|
@ -896,7 +973,7 @@ class Sensor(Connect):
|
|||
hostname: str, username: str, userpass: str,
|
||||
nodetype: str, nodename: str,
|
||||
hostport: int = 22
|
||||
) -> None:
|
||||
) -> None:
|
||||
"""Object constructor.
|
||||
|
||||
Args:
|
||||
|
@ -929,6 +1006,7 @@ class Sensor(Connect):
|
|||
username=self._user, password=self._pswd
|
||||
)
|
||||
|
||||
# pylint: disable=W0718
|
||||
def __temperature(self, nodename: str) -> str:
|
||||
"""Preparating request for ds18b20 sensor type.
|
||||
|
||||
|
@ -969,21 +1047,25 @@ class Sequence:
|
|||
"""Sequence handling.
|
||||
"""
|
||||
@staticmethod
|
||||
# pylint: disable=W0718
|
||||
def run(
|
||||
device: HikISAPI, sensors: dict, sequence: dict,
|
||||
records_root_path: str = None,
|
||||
records_root_user: str = None,
|
||||
records_root_pass: str = None
|
||||
) -> None:
|
||||
) -> None:
|
||||
"""Sequences executor.
|
||||
|
||||
Args:
|
||||
device (HikISAPI): HikISAPI object.
|
||||
sensors (dict): collection as key=sensorname:value=Sensor object.
|
||||
sequence (dict): sequence steps collection.
|
||||
records_root_path (str, optional): path (local|smb|ftp,sftp) to records directory. Defaults to None.
|
||||
records_root_user (str, optional): username if path on remote host. Defaults to None.
|
||||
records_root_pass (str, optional): password if path on remote host. Defaults to None.
|
||||
records_root_path (str, optional): path (local|smb|ftp,sftp) to records directory.
|
||||
Defaults to None.
|
||||
records_root_user (str, optional): username if path on remote host.
|
||||
Defaults to None.
|
||||
records_root_pass (str, optional): password if path on remote host.
|
||||
Defaults to None.
|
||||
"""
|
||||
for key, value in sequence.items():
|
||||
action = value.split(',')[0].strip()
|
||||
|
@ -1002,12 +1084,12 @@ class Sequence:
|
|||
m = sensor_value
|
||||
else:
|
||||
m = ''
|
||||
logging.info(
|
||||
msg=' action:' + key + ' = ' + action
|
||||
logging.info(msg=''
|
||||
+ ' action:' + key + ' = ' + action
|
||||
+ ',' + x + ',' + y + ',' + z
|
||||
+ ',' + p + ',' + s + ',' + t
|
||||
+ ',' + w + ',' + m
|
||||
)
|
||||
)
|
||||
if action == 'capabilities':
|
||||
response = device.capabilities()
|
||||
elif action == 'getcamerapos':
|
||||
|
@ -1052,8 +1134,14 @@ class Sequence:
|
|||
th = datetime.now().strftime('%H')
|
||||
tm = datetime.now().strftime('%M')
|
||||
ts = datetime.now().strftime('%S')
|
||||
records_file_name = (key + '_' + dy + '-' + dm + '-' + dd + '_' + th + '.' + tm + '.' + ts + '.jpeg')
|
||||
if device.downloadjpeg(x=int(x), y=int(y), dst_file=records_root_temp + sep + records_file_name):
|
||||
records_file_name = (
|
||||
key + '_' + dy + '-' + dm + '-' + dd + '_' + th + '.' + tm + '.' + ts + '.jpeg'
|
||||
)
|
||||
if device.downloadjpeg(
|
||||
x=int(x),
|
||||
y=int(y),
|
||||
dst_file=records_root_temp + sep + records_file_name
|
||||
):
|
||||
hostname = 'localhost'
|
||||
hostport, hosttype = None, None
|
||||
username = records_root_user
|
||||
|
@ -1078,7 +1166,11 @@ class Sequence:
|
|||
hostname = hostname.split(':')[0]
|
||||
if hosttype == 'ftp':
|
||||
src_file = records_root_temp + sep + records_file_name
|
||||
dst_file = hostpath + '/' + dy + '/' + dm + '/' + dv + '/' + dd + '/' + records_file_name
|
||||
dst_file = (
|
||||
hostpath
|
||||
+ '/' + dy + '/' + dm + '/' + dv + '/' + dd + '/'
|
||||
+ records_file_name
|
||||
)
|
||||
if Connect.ftp_put_file(
|
||||
src_file=src_file,
|
||||
dst_file=dst_file,
|
||||
|
@ -1092,7 +1184,11 @@ class Sequence:
|
|||
pass
|
||||
elif hosttype == 'sftp':
|
||||
src_file = records_root_temp + sep + records_file_name
|
||||
dst_file = hostpath + '/' + dy + '/' + dm + '/' + dv + '/' + dd + '/' + records_file_name
|
||||
dst_file = (
|
||||
hostpath
|
||||
+ '/' + dy + '/' + dm + '/' + dv + '/' + dd + '/'
|
||||
+ records_file_name
|
||||
)
|
||||
response = Connect.ssh_put_file(
|
||||
src_file=src_file, dst_file=dst_file,
|
||||
hostname=hostname, port=hostport,
|
||||
|
@ -1107,18 +1203,23 @@ class Sequence:
|
|||
response = False
|
||||
else:
|
||||
src_file = records_root_temp + sep + records_file_name
|
||||
dst_file = hostpath + sep + dy + sep + dm + sep + dv + sep + dd + sep + records_file_name
|
||||
dst_file = (
|
||||
hostpath
|
||||
+ sep + dy + sep + dm + sep + dv + sep + dd + sep
|
||||
+ records_file_name)
|
||||
try:
|
||||
makedirs(hostpath + sep + dy + sep + dm + sep + dv + sep + dd, exist_ok=True)
|
||||
makedirs(
|
||||
hostpath + sep + dy + sep + dm + sep + dv + sep + dd,
|
||||
exist_ok=True
|
||||
)
|
||||
replace(src=src_file, dst=dst_file)
|
||||
response = True
|
||||
except Exception as error:
|
||||
logging.debug(
|
||||
msg=''
|
||||
logging.debug(msg=''
|
||||
+ '\n' + 'src_file: ' + src_file
|
||||
+ '\n' + 'dst_file: ' + dst_file
|
||||
+ '\n' + 'error: ' + str(error)
|
||||
)
|
||||
)
|
||||
response = False
|
||||
else:
|
||||
response = False
|
||||
|
@ -1134,6 +1235,7 @@ class Proc:
|
|||
"""Find a running process from Python.
|
||||
"""
|
||||
@classmethod
|
||||
# pylint: disable=W0612
|
||||
def _list_windows(cls) -> list:
|
||||
"""Find all running process with wmi.
|
||||
|
||||
|
@ -1174,6 +1276,7 @@ class Proc:
|
|||
return execlist
|
||||
|
||||
@classmethod
|
||||
# pylint: disable=W0612
|
||||
def _list_linux(cls) -> list:
|
||||
"""Find all running process with ps.
|
||||
|
||||
|
@ -1219,6 +1322,7 @@ class Proc:
|
|||
return None
|
||||
|
||||
@classmethod
|
||||
# pylint: disable=W0150
|
||||
def search(cls, find: str, exclude: str = None) -> list:
|
||||
"""Find specified processes.
|
||||
|
||||
|
@ -1301,12 +1405,12 @@ class FFmpeg:
|
|||
int: ffmpeg return code
|
||||
"""
|
||||
if not raw:
|
||||
process = (''
|
||||
process = ([]
|
||||
+ cls._bin(ffpath).split()
|
||||
+ cls._src(src).split()
|
||||
+ cls._preset(preset, fps).split()
|
||||
+ cls._dst(dst).split()
|
||||
)
|
||||
)
|
||||
else:
|
||||
process = cls._bin(ffpath).split() + raw.split()
|
||||
|
||||
|
@ -1328,7 +1432,7 @@ class FFmpeg:
|
|||
print(line, flush=True)
|
||||
else:
|
||||
que.put(line)
|
||||
return proc.returncode
|
||||
return proc.returncode
|
||||
|
||||
@classmethod
|
||||
def _bin(cls, ffpath: str, tool: str = 'ffmpeg') -> str:
|
||||
|
@ -1350,11 +1454,11 @@ class FFmpeg:
|
|||
'\tTarget: /usr/bin/ffmpeg\n'
|
||||
'\n'
|
||||
'Install on Windows:\n'
|
||||
'\tDownload and extract archive from: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z\n'
|
||||
'\tDownload and extract: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z\n'
|
||||
'\tTarget: "%PROGRAMFILES%\\ffmpeg\\bin\\ffmpeg.exe"\n'
|
||||
'\n'
|
||||
'Install on MacOS:\n'
|
||||
'\tDownload and extract archive from: https://evermeet.cx/ffmpeg/\n'
|
||||
'\tDownload and extract: https://evermeet.cx/ffmpeg/\n'
|
||||
'\tTarget: /usr/bin/ffmpeg\n'
|
||||
)
|
||||
if not ffpath:
|
||||
|
@ -1565,7 +1669,8 @@ if __name__ == "__main__":
|
|||
'- Python 3 (tested version 3.9.5), '
|
||||
'- Python 3 modules: paramiko '
|
||||
)
|
||||
args.add_argument('--config', type=str, default=path.splitext(__file__)[0] + '.conf', required=False,
|
||||
args.add_argument('--config', type=str, default=path.splitext(__file__)[0] + '.conf',
|
||||
required=False,
|
||||
help='custom configuration file path')
|
||||
args.add_argument('-b', '--broadcast', action='store_true', required=False,
|
||||
help='streaming media to destination')
|
||||
|
|
Loading…
Reference in New Issue
Block a user