From 66cdc38ca63b578049e577c40e8720dc630e9734 Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Fri, 30 Aug 2024 12:43:10 +0530 Subject: [PATCH] add new asset actions and clenup asset_monitor task (#2411) Co-authored-by: Vignesh Hari <14056798+vigneshhari@users.noreply.github.com> --- care/facility/api/viewsets/asset.py | 1 + care/facility/tasks/asset_monitor.py | 53 ++++++++++++++++------- care/utils/assetintegration/base.py | 15 +++++-- care/utils/assetintegration/hl7monitor.py | 10 +++++ care/utils/assetintegration/onvif.py | 9 ++++ care/utils/assetintegration/ventilator.py | 10 +++++ 6 files changed, 78 insertions(+), 20 deletions(-) diff --git a/care/facility/api/viewsets/asset.py b/care/facility/api/viewsets/asset.py index 42323de545..4f33bc6225 100644 --- a/care/facility/api/viewsets/asset.py +++ b/care/facility/api/viewsets/asset.py @@ -389,6 +389,7 @@ def operate_assets(self, request, *args, **kwargs): asset_class: BaseAssetIntegration = AssetClasses[asset.asset_class].value( { **asset.meta, + "id": asset.external_id, "middleware_hostname": middleware_hostname, } ) diff --git a/care/facility/tasks/asset_monitor.py b/care/facility/tasks/asset_monitor.py index df302b399e..f3b50a87c6 100644 --- a/care/facility/tasks/asset_monitor.py +++ b/care/facility/tasks/asset_monitor.py @@ -4,6 +4,7 @@ from celery import shared_task from django.contrib.contenttypes.models import ContentType +from django.db.models import Q from django.utils import timezone from care.facility.models.asset import Asset, AvailabilityRecord, AvailabilityStatus @@ -17,12 +18,25 @@ def check_asset_status(): logger.info(f"Checking Asset Status: {timezone.now()}") - assets = Asset.objects.all() + assets = ( + Asset.objects.exclude(Q(asset_class=None) | Q(asset_class="")) + .select_related( + "current_location", + "current_location__facility", + ) + .only( + "external_id", + "meta", + "asset_class", + "current_location__middleware_address", + "current_location__facility__middleware_address", + ) + ) asset_content_type = ContentType.objects.get_for_model(Asset) for asset in assets: - # Skipping if asset class or local IP address is not present - if not asset.asset_class or not asset.meta.get("local_ip_address", None): + # Skipping if local IP address is not present + if not asset.meta.get("local_ip_address", None): continue try: # Fetching middleware hostname @@ -49,24 +63,31 @@ def check_asset_status(): ].value( { **asset.meta, + "id": asset.external_id, "middleware_hostname": resolved_middleware, } ) # Fetching the status of the device if asset.asset_class == "ONVIF": - asset_config = asset.meta["camera_access_key"].split(":") - assets_config = [ - { - "hostname": asset.meta.get("local_ip_address"), - "port": 80, - "username": asset_config[0], - "password": asset_config[1], - } - ] - - result = asset_class.api_post( - asset_class.get_url("cameras/status"), data=assets_config - ) + try: + # TODO: Remove this block after all assets are migrated to the new middleware + asset_config = asset.meta["camera_access_key"].split(":") + assets_config = [ + { + "hostname": asset.meta.get("local_ip_address"), + "port": 80, + "username": asset_config[0], + "password": asset_config[1], + } + ] + + result = asset_class.api_post( + asset_class.get_url("cameras/status"), data=assets_config + ) + except Exception: + result = asset_class.api_get( + asset_class.get_url("cameras/status") + ) else: result = asset_class.api_get(asset_class.get_url("devices/status")) except Exception as e: diff --git a/care/utils/assetintegration/base.py b/care/utils/assetintegration/base.py index 92d318c3a5..d43690b39d 100644 --- a/care/utils/assetintegration/base.py +++ b/care/utils/assetintegration/base.py @@ -12,6 +12,7 @@ class BaseAssetIntegration: def __init__(self, meta): self.meta = meta + self.id = self.meta.get("id", "") self.host = self.meta["local_ip_address"] self.middleware_hostname = self.meta["middleware_hostname"] self.insecure_connection = self.meta.get("insecure_connection", False) @@ -25,11 +26,17 @@ def get_url(self, endpoint): protocol += "s" return f"{protocol}://{self.middleware_hostname}/{endpoint}" + def get_headers(self): + return { + "Authorization": (self.auth_header_type + generate_jwt()), + "Accept": "application/json", + } + def api_post(self, url, data=None): req = requests.post( url, json=data, - headers={"Authorization": (self.auth_header_type + generate_jwt())}, + headers=self.get_headers(), ) try: response = req.json() @@ -37,13 +44,13 @@ def api_post(self, url, data=None): raise APIException(response, req.status_code) return response except json.decoder.JSONDecodeError: - return {"error": "Invalid Response"} + raise APIException({"error": "Invalid Response"}, req.status_code) def api_get(self, url, data=None): req = requests.get( url, params=data, - headers={"Authorization": (self.auth_header_type + generate_jwt())}, + headers=self.get_headers(), ) try: if req.status_code >= 400: @@ -51,4 +58,4 @@ def api_get(self, url, data=None): response = req.json() return response except json.decoder.JSONDecodeError: - return {"error": "Invalid Response"} + raise APIException({"error": "Invalid Response"}, req.status_code) diff --git a/care/utils/assetintegration/hl7monitor.py b/care/utils/assetintegration/hl7monitor.py index f7f1e7c783..fffe61c963 100644 --- a/care/utils/assetintegration/hl7monitor.py +++ b/care/utils/assetintegration/hl7monitor.py @@ -10,6 +10,7 @@ class HL7MonitorAsset(BaseAssetIntegration): class HL7MonitorActions(enum.Enum): GET_VITALS = "get_vitals" + GET_STREAM_TOKEN = "get_stream_token" def __init__(self, meta): try: @@ -26,4 +27,13 @@ def handle_action(self, action): request_params = {"device_id": self.host} return self.api_get(self.get_url("vitals"), request_params) + if action_type == self.HL7MonitorActions.GET_STREAM_TOKEN.value: + return self.api_post( + self.get_url("api/stream/getToken/vitals"), + { + "asset_id": self.id, + "ip": self.host, + }, + ) + raise ValidationError({"action": "invalid action type"}) diff --git a/care/utils/assetintegration/onvif.py b/care/utils/assetintegration/onvif.py index 8e21c77d43..6b26053f0b 100644 --- a/care/utils/assetintegration/onvif.py +++ b/care/utils/assetintegration/onvif.py @@ -14,6 +14,7 @@ class OnvifActions(enum.Enum): GOTO_PRESET = "goto_preset" ABSOLUTE_MOVE = "absolute_move" RELATIVE_MOVE = "relative_move" + GET_STREAM_TOKEN = "get_stream_token" def __init__(self, meta): try: @@ -54,4 +55,12 @@ def handle_action(self, action): if action_type == self.OnvifActions.RELATIVE_MOVE.value: return self.api_post(self.get_url("relativeMove"), request_body) + if action_type == self.OnvifActions.GET_STREAM_TOKEN.value: + return self.api_post( + self.get_url("api/stream/getToken/videoFeed"), + { + "stream_id": self.access_key, + }, + ) + raise ValidationError({"action": "invalid action type"}) diff --git a/care/utils/assetintegration/ventilator.py b/care/utils/assetintegration/ventilator.py index 10af39b50f..a74ec0deb0 100644 --- a/care/utils/assetintegration/ventilator.py +++ b/care/utils/assetintegration/ventilator.py @@ -10,6 +10,7 @@ class VentilatorAsset(BaseAssetIntegration): class VentilatorActions(enum.Enum): GET_VITALS = "get_vitals" + GET_STREAM_TOKEN = "get_stream_token" def __init__(self, meta): try: @@ -26,4 +27,13 @@ def handle_action(self, action): request_params = {"device_id": self.host} return self.api_get(self.get_url("vitals"), request_params) + if action_type == self.VentilatorActions.GET_STREAM_TOKEN.value: + return self.api_post( + self.get_url("api/stream/getToken/vitals"), + { + "asset_id": self.id, + "ip": self.host, + }, + ) + raise ValidationError({"action": "invalid action type"})