U
    —âñju‡  ã                   @   sš   d dl Z d dlZdd„ Zd%dd„Zdd„ Zd	d
„ Zdd„ Zdd„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zd&dd„Zdd„ Zd d!„ Zd'd#d$„ZdS )(é    Nc                 C   s   t | ƒ d S )N)Úprint)Útext© r   úE/var/www/itgmanager/itgmanager/Analytic/utils/Scapp_analytic_utils.pyÚdata_analytic_logger   s    r   Tc           $         sà  i }d}|› d�}|› d�}	d}
t j  ||
¡}t j  |	|
¡}d}| di ¡ dd¡}|  ¡ D �]f\}}�zi }g }g }d	}d
}g }g }t j  ||
¡}|D �]}|d }|d }| dd¡}|d }t j  | d¡d
 ¡}|d }t|||||ƒ\}}| dd
¡}t||ƒ}||  k�o|kn  �p0| dd¡} | �r†| |d ¡ || j	|k�r†t
|ƒd
k�r†|}| | ¡ t |¡dœ¡ g }t||||||| |ƒ q˜t|ƒ t| |g ¡|||ƒ\}!}"|!d |!d ||!d dœdd„ | ¡ D ƒ|t
| |g ¡ƒdœ–‰|||!d |!d |"|dœdd„ | ¡ D ƒd ‡fd!d„tˆ ¡ ƒD ƒi–‰ d"| ||¡i‡ fd#d„tˆ  ¡ ƒD ƒ–||< W q\ tk
�rÂ }# z*td$|› d%|› d&|#jj› d'|#› d(�	ƒ W 5 d	}#~#X Y q\X q\|�rÜtd)|› d(�ƒ |S )*ué   ### ? Recibe los datos de un dia completo de analisis y los formatea para mostrar en el mÃ³dulo de analÃ­tica
    @params
        - day_data (dict): Diccionario con datos del dÃ­a por jaula, de la forma { cam_index: [data...], ... }
            Cada 'data' es de la forma:
                [
                    {
                        timestamp: 2024-06-27T12:03:26.000+00:00,
                        camera_id: "1-A",
                        Detecciones: {
                            perdidos: 0,
                            detectados: 0,
                            nivel_actividad: 26.04,
                            umbral_alarma: 3,
                            perdidos_propios: 0,
                        },
                        Alimentacion: {
                            use_feeding_api: false,
                            detection_active: false,
                            Comida_entregada: 0,
                            Meta_dia: 0,
                            Porc_entregado: 0,
                            Tasa: 0,
                            Dia: 0,
                            Feeding_active: false,
                            Unidad_Medida: "kg/min",
                            Metodo_alimentacion: "Saciedad",
                            feeding_api_type: "AkvaControl",
                        },
                        Posicion: {
                            x_pos: "-",
                            y_pos: "-",
                            winche_connected: false,
                        },
                        Sensores: {
                            temp: "-"
                        }
                    } , ... 
                ]
    @return
        - analytic_data (dict): Diccionario de los datos del dÃ­a por jaula
            { jaula: { sfr_value, delivered_food, tasa_units, tasa_values,  tasa_data, fasts_count, feeding_time_range, alarms_data, alarms_count } }
            Cada llave es un diccionario, con el formato:
                { 'day' : 'dd/mm/yyyy , 'value': ... }
    Fz	 07:30:00z	 22:30:00z%d/%m/%Y %H:%M:%Siƒ  ZAnalytic_alarm_gap_timeÚvalueé   Nr   ZDeteccionesZAlimentacionZuse_feeding_apiÚ	timestampú+Úumbral_alarmaÚperdidosZFeeding_activeÚnivel_actividad)Útimer   Úalarms_by_tonÚalarms_countÚ
today_fast)r   r   Úalarms_thresholdÚfasts_countc                 S   s   i | ]\}}|d kr||“qS ©Útasa_valuesr   ©Ú.0ÚkÚvr   r   r   Ú
<dictcomp>œ   s       z(process_one_day_data.<locals>.<dictcomp>)Úperdidos_coutÚvisitas_coutÚfeeding_time_rangeÚalarms_by_tasa)Úactivity_dataÚalarms_datar   r   Úalarms_by_tasa_levelsÚ	tasa_datac                 S   s   i | ]\}}|d kr||“qS r   r   r   r   r   r   r   §   s       Úvalues_summaryc                    s   i | ]}|ˆ | “qS r   r   ©r   r   )Ú_values_summaryr   r   r   ©   s      Únamec                    s   i | ]}|ˆ | “qS r   r   r$   )Ú_analytic_datar   r   r   ³   s      zError calculando z del z (ú): Ú u0   Se ha computado correctamente la AnalÃ­tica del )ÚdatetimeÚstrptimeÚgetÚitemsÚfromisoformatÚsplitÚ_verify_alarm_eventÚmaxÚappendÚsecondsÚlenÚ	isoformatÚ
statisticsÚmeanÚ_update_feeding_dataÚ_verify_tasa_dataÚfeeding_metricsÚsortedÚkeysÚ	Exceptionr   Ú__traceback__Ú	tb_lineno)$Úday_dataÚ
day_visitsÚformatted_dayÚcam_names_dictÚscapp_configsÚverboseÚanalytic_dataÚhave_feeding_dataZstr_start_activityZstr_end_activityÚformatoZstart_activityZend_activityZseconds_to_save_activityÚ	alarm_gapZcam_idxZcam_dataÚcam_feeding_dataÚcam_detection_datar"   Úlast_detect_thresholdZtotal_perdidosr   Zactivity_bufferZlast_saved_activityÚdocumentÚdetection_docÚfeeding_docr	   Zdt_timestampÚadded_detection_datar   Úvalid_feed_hourZfed_metricsÚquantized_alarmsÚer   )r'   r%   r   Úprocess_one_day_data   s¤    .


   ÿ
(
ÿ

   ÿû÷ú ÷ 
ûú: rT   c                 C   sz   d}|d }|d |krrd}t | ƒdkr6t| ||ƒ n<| d d }t|||ƒr\t| ||ƒ nt| ||d |d ƒ ||fS )	uß   ### ? Verifica si hubo alarma durante el instante entregado, si es asÃ­, aÃ±ade el evento a cam_detection_data
    @params
        - cam_detection_data ([dict])   : Array de diccionario con eventos de alarmas.
        - detection_doc (dict)          : Datos de detecciones correspondiente al instante analizado (con resoluciÃ³n mÃ¡xima de 2s).
        - timestamp (datetime)          : Timestamp como objeto datetime.
        - last_detect_threshold (int)   : Ãšltimo valor de treshold en BD, se actualiza en cada iteraciÃ³n.
        - added_detection_data (bool)   : Flag que indica si se aÃ±adiÃ³ un evento de alarma.
        - alarm_gap (int)               : Tiempo, en segundos, para considerar 2 eventos como independientes.
    Fr   Ú
detectadosTr   éÿÿÿÿÚendr   )r4   Ú_append_new_alarm_eventÚ_verify_independent_alarm_eventÚ_update_alarm_event)rK   rN   r	   rL   rI   rP   Úlast_timestampr   r   r   r0   ¾   s    
r0   c                 C   s&   t j  |¡}t j  | ¡}|| j|kS )a—   ### ? Verifica si el evento de alarma se considera un evento independiente, o debe actualizarse el evento anterior.
    
    @params
        - last_timestamp (datetime)     : Timestamp anterior, como objeto datetime.
        - timestamp (datetime)          : Timestamp, como objeto datetime.
        - alarm_gap (int)               : Tiempo, en segundos, para considerar 2 eventos como independientes.
    )r*   r.   r3   )r[   r	   rI   ÚtsZlast_tsr   r   r   rY   Ý   s    rY   c              	   C   s$   |   ||d|d |d ddœ¡ dS )uc   ### ? AÃ±ade un nuevo evento de detecciÃ³n
    @params
        - cam_detection_data ([dict])   : Array de diccionario con eventos de alarmas.
        - detection_doc (dict)          : Datos de detecciones correspondiente al instante analizado (con resoluciÃ³n mÃ¡xima de 2s).
        - timestamp (datetime)          : Timestamp como objeto datetime.
    é   rU   r   r   )ÚstartrW   ÚdurationrU   r   Ú
tasa_valueN)r2   )rK   rN   r	   r   r   r   rX   ê   s    úrX   c           	      C   sj   | d d }| d d }| d d }t j  |¡}t j  |¡}| d  ||| jt||ƒt||ƒdœ¡ dS )ub   ### ? Actualiza un nuevo evento de detecciÃ³n:
        -   Modifica timestamp de tÃ©rmino
        -   Modifica duraciÃ³n del evento
        -   Almacena como nivel de actividad el mÃ¡ximo entre los eventos.
        -   Almacena como detectados el mÃ¡ximo entre los eventos.
        
    @params
        - cam_detection_data ([dict])   : Array de diccionario con eventos de alarmas.
        - timestamp (datetime)          : Timestamp como objeto datetime.
        - detectados (int)              : Valor de detecciones actual.
        - nivel_actividad (int)         : Valor de nivel de actividad actual.
    rV   r^   r   rU   )rW   r_   r   rU   N)r*   r.   Úupdater3   r1   )	rK   r	   rU   r   Ú
start_timeZlast_activityZlast_detectadosZstart_tsZ	actual_tsr   r   r   rZ   û   s    ü	rZ   c                 C   s:  |  d¡}|dkrd}|  dg ¡}	||	kr4|	 |¡ |s@|dkrÜ|rÜt| ƒdkrb|  ||dœ¡ nz| d d }
t| ƒdk rŒ|  ||dœ¡ nP|
|kr¦|  ||dœ¡ n6| d d | d	 d krÌ|| d d
< n|  ||dœ¡ |�r
|d   dd¡}|d  dt||ƒi¡ | |  dd¡|  dd¡|  dd¡|	dœ¡ dS )uw   ### ? Actualiza los datos de alimentaciÃ³n: 
            - AÃ±ade o modifica el timestamp de Tasa para el grÃ¡fico
            - Actualiza dato de tasa en evento de alarma, en caso de haber evento de alarma 
    @params
        - tasa_data ([dict])             : Datos de tasa para grÃ¡fico, cada elemento contiene value y timestamp.
        - cam_feeding_data (dict)       : Almacena los datos de alimentacion: { sfr_value, delivered_food, tasa_units, tasa_values }
                sfr_value      (float)  : Valor de sft del dÃ­a, se actualiza en cada iteraciÃ³n, corresponde a un porcentaje, que puede y suele superar 100%
                delivered_food (float)  : Valor de comida entregada, en kg 
                tasa_units     (str)    : Unidades de medida de la tasa (kg/min , pellet/pez/minuto, ppv, etc)
                tasa_values    ([float]): Valores de tasa de alimentaciÃ³n de la jornada.
        - feeding_doc (dict)            : Datos de alimentaciÃ³n correspondiente al instante analizado (con resoluciÃ³n mÃ¡xima de 2s).
        - timestamp (datetime)          : Timestamp como objeto datetime.
        - cam_detection_data ([dict])   : Array de diccionario con eventos de alarmas.
        - added_detection_data (bool)   : Flag que indica si se aÃ±adiÃ³ un evento de alarma.
        - valid_feed_hour (bool)        : Flag que indica si se estÃ¡ en un rango aceptado de horas 
    ZTasaNr   r   ©r   r   rV   r   r]   éþÿÿÿr   r`   ZComida_entregadaZPorc_entregadoZUnidad_Medidazkg/min)Údelivered_foodÚ	sfr_valueÚ
tasa_unitsr   )r,   r2   r4   ra   r1   )r"   rJ   rO   r	   rK   rP   rQ   rG   Zactual_tasar   Zlast_graph_tasaZlast_det_tasar   r   r   r8     s6    
 



ür8   c                 C   sr   t | ƒdkrn| d d }|dkrn| d d }t|ƒtkrFtj |¡}n|}|tjdd�  ¡ }|  d|dœ¡ dS )	uÎ    ### ? Asegura que la tasa siempre termine en 0, en caso de tener datos
        @params
        - tasa_data ([dict])             : Datos de tasa para grÃ¡fico, cada elemento contiene value y timestamp.
    r   rV   r   r   é   )r3   rc   N)r4   ÚtypeÚstrr*   r.   Ú	timedeltar5   r2   )r"   Ú
last_valuer[   r\   Zone_second_laterr   r   r   r9   q  s    r9   c                 C   s`   t | ƒ\}}t|||ƒ\}}t|ƒ}| dd¡}	|	dkrD||	 d nd}
||||
|dœ}||fS )uQ   ### ? Calcula todas las mÃ©tricas adicionales de alimentaciÃ³n
    @params:
    - day_visits            [dict]  : Array que contiene diccionarios de visitas, cada uno de la forma:
        day: "2024-10-17",
        camera_id: "13-A",
        Visitas: [
            duracion: 75.04, 
            racion: 0, 
            inicio: 2024-10-17T17:23:05.000+00:00, -> datetime
            final: 2024-10-17T17:24:20.000+00:00            
        ]
    - cam_feeding_data      (dict)  : { sfr_value, delivered_food, tasa_units, tasa_values }
    - cam_detection_data    ([dict]): [ {start, end, duration, detectados, nivel_actividad, tasa_value }, ... ]
    @return
    - today_fast                (float)     : Ayuno del dÃ­a [0, 0.5, 1.0]
    - feeding_time_range        {str(isoformat)}  : Diccionario de timestamp de alimentaciÃ³n: {inicio, final}
    re   r   g     @�@)r   r   r   r   r   )Ú _calculate_fasts_and_time_rangesÚ!_calculate_alarms_by_feeding_rater4   r,   )rA   rJ   rK   rD   r   r   r   rR   r   re   r   r:   r   r   r   r:   †  s    ûr:   c           
   
   C   s0  d}i }t | ƒdk�r(| d }| d }zD|d }t|tƒrFtj |¡}|j}|dk r\|d8 }| ¡ |d< W n: tk
r¤ } ztd|j	j
› d|› �ƒ W 5 d	}~X Y nX zD|d
 }t|tƒrÆtj |¡}|j}	|	dkrÜ|d8 }| ¡ |d
< W n< tk
�r& } ztd|j	j
› d|› �ƒ W 5 d	}~X Y nX ||fS )uú    ### ? Calcula y retorna el ayuno del dÃ­a
    @return
    - today_fast                (float)     : Ayuno del dÃ­a [0, 0.5, 1.0]
    - feeding_time_range        (dict)      : {
        inicio: str(isoformat),
        final: str(isoformat)
    }
    g      ð?r   rV   Úinicioé   g      à?u#   Error calculando ayuno de maÃ±ana (r(   NÚfinalz!Error calculando ayuno de tarde ()r4   Ú
isinstancerj   r*   r.   Úhourr5   r=   r   r>   r?   )
rA   Úayunor   Z	breakfastZdinnerZbreakfast_timestampZbreakfast_timerS   Zdinner_timestampZdinner_timer   r   r   rm   «  s4    	
*
*rm   c                 C   sš   ddddœ}t | |ƒ}|D ]v}| d¡}|dkrDtd|› d�ƒ d}||d krb|d  d7  < q||d	 kr€|d	  d7  < q|d
  d7  < q||fS )aÁ   ### ? Calcula la cantidad de alarmas por tasa, separadas en 3 niveles: Alarmas a tasa [baja, media, alta] 
    @params:
    - cam_feeding_data      (dict)  :   { sfr_value, delivered_food, tasa_units, tasa_values }
    - cam_detection_data    ([dict]):   [ {start, end, duration, detectados, nivel_actividad, tasa_value }, ... ]
    @return
    - alarms_by_tasa        (dict)     : Cantidad de alarma por tasas cuantizadas: {baja, media, alta}
    r   ©ÚbajaÚmediaÚaltar`   NuD   Warning: Tasa no encontrada en evento de detecciÃ³n, seteando a 0: 
r)   rx   rh   rw   rv   )Ú_discretize_feeding_ratesr,   r   )rJ   rK   rD   r   rR   Zdetect_eventZ
event_tasar   r   r   rn   Ü  s     
ý

rn   c              
      sä  d}dgg g dœ}�zŒd| kr$|W S | d }dd„ |D ƒ‰ t ˆ ƒ}|dkrPW dS |dk�r|d	kr¾ˆ  ¡  ˆ d ˆ d
 ˆ d	   }}}||d kr |d  |¡ |d  |¡ |d  |¡ nX|d	krötˆ ƒtˆ ƒ }}|d  |¡ |d  |¡ n |d
k�rvˆ d }	|d  |	¡ �n\dg}
g }g }‡ fdd„ˆ D ƒ}tˆ ƒdt|ƒ k�rttdtˆ ƒ› �ƒ | tˆ ƒ¡ |‰ | di ¡ dd¡}tˆ |ƒ\}}|�o¢ˆ  ¡  tdˆ › dt	|d
ƒt	|d
ƒf› �ƒ ˆ D ]Z}||k�rð||
k�r$|
 |¡ n4||k�r||k�r$| |¡ n||k�rÌ| |¡ �qÌt |
ƒdk�r>|
 ¡  t |ƒdk�rT| ¡  t |ƒdk�rj| ¡  |
||dœ}t |d ƒdk�rž|�oœtd|›d�ƒ W n> t
k
�rÞ } ztd|jj› d|› d�ƒ W 5 d}~X Y nX |S )u×   ### ? Cuantizar las tasas de alimentaciÃ³n del dÃ­a en 3 niveles: {baja, media, alta}
        Si existen mÃ¡s de 3 tasas de alimentaciÃ³n, los niveles se definen como:
            - baja:     [ min_value , mean - std/2 ]
            - media:    ] mean - std/2, mean + std/2 [
            - alta:     [ mean + std/2, max_value ]
        
        @return 
        - quantized_alarms (dict): Diccionario con tasas cuantizadas: {baja: [], media: [], alta: [] }
        
    Fr   ru   r   c                 S   s   g | ]}|d kr|‘qS ©r   r   ©r   Útr   r   r   Ú
<listcomp>  s      z-_discretize_feeding_rates.<locals>.<listcomp>Né   r]   rh   rv   rw   rx   c                    s   g | ]}|t ˆ ƒk r|‘qS r   )r1   r{   r   r   r   r}   <  s      é
   z.Warning: Tasa excesivamente grande detectada: ZAnalytic_discr_methodr   Zwide_mediumu%   Rango de tasas, hay mÃ¡s de 3 tasas: z -> z	quantized_alarms=Ú
u5   Error discretizando rangos de Tasa de AlimentaciÃ³n (r(   r)   )r4   Úsortr2   Úminr1   r   r,   Úcompute_discrete_rangesr   Úroundr=   r>   r?   )rJ   rD   ÚdebugrR   Ú_tasa_valuesZtasa_values_lenZmin_tasaZmid_tasaZmax_tasaÚtasaZ
baja_arrayZmedia_arrayZ
alta_arrayZconfig_methodZ
rango_bajoZ
rango_altoZtasa_valrS   r   r   r   ry     s€    ý 
 
 $




   ý ,ry   r]   c                 C   s>   dd„ | D ƒ}|dkr t |ƒ}n|dkr2t|ƒ}nt|ƒ}|S )zo Calcula los cortes para dividir las tasas en 3
    - Methods : ['equal_ranges', 'wide_medium', 'normal'] 
    c                 S   s   g | ]}|d kr|‘qS rz   r   r{   r   r   r   r}   p  s      z+compute_discrete_ranges.<locals>.<listcomp>ÚnormalZequal_ranges)Ú_asumming_normal_distÚ_equal_rangesÚ_wide_medium_ranges)r†   Úmethodr   Zrangosr   r   r   rƒ   l  s    

rƒ   c                 C   s4   t  | ¡}t  | ¡}||d  }||d  }||gS )u’    Calcula rangos asumiendo distribuciÃ³n normal ( mu +- D.E. )
    - Menor a DE - prom -> aÃ±adir a baja
    - Mayor a DE + prom -> aÃ±adir a alta r]   )r6   Ústdevr7   )r   r�   r7   Zstd_plus_meanZstd_minus_meanr   r   r   r‰   ~  s
    

r‰   c                 C   s0   t | ƒ}t| ƒ| }|d }|| ||d  gS )z( Se divide el rango en 3 partes iguales r~   r]   ©r‚   r1   )r   Ú	min_valueÚrangoÚstepr   r   r   rŠ   ‹  s    rŠ   çÍÌÌÌÌÌÜ?c                 C   s<   t | ƒ}t| ƒ}|| }d| }|d | }|| || gS )zh Se le asigna al rango central un mayor porcentaje del rango, definido mediante medium_range_percentage rh   r]   rŽ   )r   Zmedium_range_percentager�   Ú	max_valuer�   Zmin_max_percentager‘   r   r   r   r‹   ”  s    r‹   )T)r]   )r’   )r*   r6   r   rT   r0   rY   rX   rZ   r8   r9   r:   rm   rn   ry   rƒ   r‰   rŠ   r‹   r   r   r   r   Ú<module>   s&   
 3"T%1(h
	
1