add retries in a couple places; cleanup; new defaults

pull/106/head
Jeff Culverhouse 11 months ago
parent ebdec66335
commit 590f110fbb

@ -1 +1 @@
0.99.25
0.99.26

@ -138,23 +138,24 @@ class AmcrestAPI(object):
privacy = device["camera"].privacy_config().split()
privacy_mode = True if privacy[0].split('=')[1] == 'true' else False
device['privacy_mode'] = privacy_mode
return privacy_mode
except CommError as err:
self.logger.error(f'Failed to communicate with device ({device_id}) to get privacy mode')
except LoginError as err:
self.logger.error(f'Failed to authenticate with device ({device_id}) to get privacy mode')
return privacy_mode
def set_privacy_mode(self, device_id, switch):
device = self.devices[device_id]
try:
return device["camera"].set_privacy(switch).strip()
response = device["camera"].set_privacy(switch).strip()
except CommError as err:
self.logger.error(f'Failed to communicate with device ({device_id}) to set privacy mode')
except LoginError as err:
self.logger.error(f'Failed to authenticate with device ({device_id}) to set privacy mode')
return response
# Motion detection config ---------------------------------------------------------------------
@ -163,23 +164,25 @@ class AmcrestAPI(object):
try:
motion_detection = device["camera"].is_motion_detector_on()
return motion_detection
except CommError as err:
self.logger.error(f'Failed to communicate with device ({device_id}) to get motion detection')
except LoginError as err:
self.logger.error(f'Failed to authenticate with device ({device_id}) to get motion detection')
return motion_detection
def set_motion_detection(self, device_id, switch):
device = self.devices[device_id]
try:
return device["camera"].set_motion_detection(switch)
response = device["camera"].set_motion_detection(switch)
except CommError as err:
self.logger.error(f'Failed to communicate with device ({device_id}) to set motion detections')
except LoginError as err:
self.logger.error(f'Failed to authenticate with device ({device_id}) to set motion detections')
return response
# Snapshots -----------------------------------------------------------------------------------
async def collect_all_device_snapshots(self):
@ -189,17 +192,24 @@ class AmcrestAPI(object):
async def get_snapshot_from_device(self, device_id):
device = self.devices[device_id]
try:
if 'privacy_mode' not in device or device['privacy_mode'] == False:
image = await device["camera"].async_snapshot()
device['snapshot'] = base64.b64encode(image)
self.logger.debug(f'Processed snapshot from ({device_id}) {len(image)} bytes raw, and {len(device['snapshot'])} bytes base64')
else:
self.logger.info(f'Skipped snapshot from ({device_id}) because "privacy mode" is ON')
except CommError as err:
tries = 0
while tries < 3:
try:
if 'privacy_mode' not in device or device['privacy_mode'] == False:
image = await device["camera"].async_snapshot()
device['snapshot'] = base64.b64encode(image)
self.logger.debug(f'Processed snapshot from ({device_id}) {len(image)} bytes raw, and {len(device['snapshot'])} bytes base64')
break
else:
self.logger.info(f'Skipped snapshot from ({device_id}) because "privacy mode" is ON')
break
except CommError as err:
tries += 1
except LoginError as err:
tries += 1
if tries == 3:
self.logger.error(f'Failed to communicate with device ({device_id}) to get snapshot')
except LoginError as err:
self.logger.error(f'Failed to authenticate with device ({device_id}) to get snapshot')
def get_snapshot(self, device_id):
return self.devices[device_id]['snapshot'] if 'snapshot' in self.devices[device_id] else None
@ -208,20 +218,26 @@ class AmcrestAPI(object):
def get_recorded_file(self, device_id, file):
device = self.devices[device_id]
try:
data_raw = device["camera"].download_file(file)
if data_raw:
data_base64 = base64.b64encode(data_raw)
self.logger.info(f'Processed recording from ({device_id}) {len(data_raw)} bytes raw, and {len(data_base64)} bytes base64')
if len(data_base64) < 100 * 1024 * 1024 * 1024:
return data_base64
else:
self.logger.error(f'Processed recording is too large')
return
except CommError as err:
self.logger.error(f'Failed to download recorded file for device ({device_id})')
except LoginError as err:
self.logger.error(f'Failed to authenticate for recorded file for device ({device_id})')
tries = 0
while tries < 3:
try:
data_raw = device["camera"].download_file(file)
if data_raw:
data_base64 = base64.b64encode(data_raw)
self.logger.info(f'Processed recording from ({device_id}) {len(data_raw)} bytes raw, and {len(data_base64)} bytes base64')
if len(data_base64) < 100 * 1024 * 1024 * 1024:
return data_base64
else:
self.logger.error(f'Processed recording is too large')
return
except CommError as err:
tries += 1
except LoginError as err:
tries += 1
if tries == 3:
self.logger.error(f'Failed to communicate with device ({device_id}) to get recorded file')
# Events --------------------------------------------------------------------------------------
@ -232,13 +248,18 @@ class AmcrestAPI(object):
async def get_events_from_device(self, device_id):
device = self.devices[device_id]
try:
async for code, payload in device["camera"].async_event_actions("All"):
await self.process_device_event(device_id, code, payload)
except CommError as err:
tries = 0
while tries < 3:
try:
async for code, payload in device["camera"].async_event_actions("All"):
await self.process_device_event(device_id, code, payload)
except CommError as err:
tries += 1
except LoginError as err:
tries += 1
if tries == 3:
self.logger.error(f'Failed to communicate for events for device ({device_id})')
except LoginError as err:
self.logger.error(f'Failed to authenticate for events for device ({device_id})')
async def process_device_event(self, device_id, code, payload):
try:

@ -22,6 +22,7 @@ from zoneinfo import ZoneInfo
class AmcrestMqtt(object):
def __init__(self, config):
self.running = False
self.paused = False
self.logger = logging.getLogger(__name__)
self.mqttc = None
@ -64,20 +65,28 @@ class AmcrestMqtt(object):
def mqtt_on_connect(self, client, userdata, flags, rc, properties):
if rc != 0:
self.logger.error(f'MQTT CONNECTION ISSUE ({rc})')
self.logger.error(f'MQTT connection issue ({rc})')
exit()
self.logger.info(f'MQTT connected as {self.client_id}')
client.subscribe(self.get_device_sub_topic())
client.subscribe(self.get_attribute_sub_topic())
def mqtt_on_disconnect(self, client, userdata, flags, rc, properties):
self.logger.info('MQTT connection closed')
self.mqttc.loop_stop()
if self.running and time.time() > self.mqtt_connect_time + 10:
self.paused = True
self.logger.info('Sleeping for 30 seconds to give MQTT time to relax')
time.sleep(30)
# lets use a new client_id for a reconnect
self.client_id = self.get_new_client_id()
self.mqttc_create()
self.paused = False
else:
self.running = False
exit()
def mqtt_on_log(self, client, userdata, paho_log_level, msg):
@ -154,6 +163,7 @@ class AmcrestMqtt(object):
callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
client_id=self.client_id,
clean_session=False,
reconnect_on_failure=False,
)
if self.mqtt_config.get('tls_enabled'):
@ -499,6 +509,7 @@ class AmcrestMqtt(object):
'payload_off': 'off',
'device_class': 'motion',
'state_topic': self.get_discovery_topic(device_id, 'motion'),
'json_attributes_topic': self.get_discovery_topic(device_id, 'motion'),
'value_template': '{{ value_json.state }}',
'unique_id': self.get_slug(device_id, 'motion'),
}
@ -671,8 +682,6 @@ class AmcrestMqtt(object):
self.logger.info(f'Failed to get recorded file from {self.get_device_name(device_id)}')
return
self.logger.info(f'Got back base64 image of {len(image)} bytes')
# only store and send to MQTT if the image has changed
if device_states['camera'][type] is None or device_states['camera'][type] != image:
device_states['camera'][type] = image
@ -781,23 +790,23 @@ class AmcrestMqtt(object):
async def collect_storage_info(self):
while self.running == True:
self.refresh_storage_all_devices()
if not self.paused: self.refresh_storage_all_devices()
if self.running: await asyncio.sleep(self.storage_update_interval)
async def collect_events(self):
while self.running == True:
await self.collect_all_device_events()
if not self.paused: await self.collect_all_device_events()
if self.running: await asyncio.sleep(1)
async def check_event_queue(self):
while self.running == True:
self.check_for_events()
if not self.paused: self.check_for_events()
if self.running: await asyncio.sleep(1)
async def collect_snapshots(self):
while self.running == True:
await self.amcrestc.collect_all_device_snapshots()
self.refresh_snapshot_all_devices()
if not self.paused: self.refresh_snapshot_all_devices()
if self.running: await asyncio.sleep(self.snapshot_update_interval)
# main loop

@ -77,12 +77,16 @@ except:
}
config['version'] = version
config['configpath'] = os.path.dirname(configpath)
# defaults
if 'username' not in config['mqtt']: config['mqtt']['username'] = ''
if 'password' not in config['mqtt']: config['mqtt']['password'] = ''
if 'qos' not in config['mqtt']: config['mqtt']['qos'] = 0
if 'timezone' not in config: config['timezone'] = 'UTC'
if 'debug' not in config: config['debug'] = os.getenv('DEBUG') or False
if 'qos' not in config['mqtt']: config['mqtt']['qos'] = 0
if 'timezone' not in config: config['timezone'] = 'UTC'
if 'debug' not in config: config['debug'] = os.getenv('DEBUG') or False
if 'hide_ts' not in config: config['hide_ts'] = os.getenv('HIDE_TS') or False
# init logging, based on config settings
logging.basicConfig(
format = '%(asctime)s.%(msecs)03d [%(levelname)s] %(name)s: %(message)s' if config['hide_ts'] == False else '[%(levelname)s] %(name)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',

Loading…
Cancel
Save