# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['nexus_api']

package_data = \
{'': ['*']}

install_requires = \
['pandas', 'requests>=2.28.1,<3.0.0']

setup_kwargs = {
    'name': 'nexus-integra-api',
    'version': '1.0.0',
    'description': ' Nexus API connection methods and utilities',
    'long_description': '# nexus_integra_api\nEste repositorio tiene como propósito reunir en una única libería todas las funciones necesarias para trabajar con la API de Nexus en Python.\nEn lugar de importar los archivos a la carpeta del proyecto cada vez que se usan puede instalarse la librería en la PATH de Python \n\n## Table of Contents\n\n* [Instalación](#instalacion)\n* [Uso](#uso)\n* [Ejemplos](#ejemplos)\n  * [Lectura de datos](#lectura)\n  * [Subida de datos](#subida)\n  * [Alarmas](#alarmas)\n  * [Email Alerts](#email)\n* [Contribuir](#contribuir)\n* [Change Log](#changelog)\n* [Contacto](#contacto)\n\n## Instalación <a class="anchor" id="instalacion"></a>\n\nUsa el package manager pip para instalar la librería. Puede instalarse de forma local o desde el repositorio de PyPi\n\n```\npip install nexus_integra_api\n```\n\n## Uso <a class="anchor" id="uso"></a>\nPara importar todo el contenido de la librería, una vez instalada hay que realizar el siguiente import:\n\n    import nexus_api\nSi únicamente se desea la clase en la que residen las funciones que trabajan con la API:\n\n    from nexus_api import APINexus\nLo que otorga acceso a la clase APINexus en la que residen todas las funciones necesarias.\n\n## Ejemplo de uso <a class="anchor" id="ejemplos"></a>\n\nEn primer lugar se especifican los parámetros de conexión y se crea el objeto Nexus, además de los imports necesarios\n```\nfrom nexus_api import APINexus\nimport pandas as pd\nimport datetime\n\nAPI_Host = \'nexus-cdi-demo.globalomnium.com\'  \nAPI_Port = 56000 \nNexusToken = \'xxxxxxxxxxxxxxxxx\' \nversion = \'v1\'\nlogger = [objeto logger - puede ser None]\nNX = APINexus.APINexus(API_Host, API_Port, NexusToken, version, logger)\n```\n\n### Lectura de datos <a class="anchor" id="lectura"></a>\n\n### filter_installation\n\n\nla funcion recibe como parametros la fecha ini, fecha fin, un df con los uid y\nlos nombres de las variables de la instalación y el filtro de texto aplicar (pueden ser varios)\n\nArgs:\n\n- Datefrom (datetime)\n- Dateto (datetime)\n- columnas (dataframe): df con los metadatos de los tags de Nexus \n- uids: (optional) (list): lista de los uids de las variables deseadas. No puede usarse con filter_txt\n- filter_txt (optional: list or str): lista de nombres de las variables deseadas. Si se deja en blanco o no se encuentran variables se devuelve toda la instalación. No puede usarse con uids\n- resolucion (int): de 0 a 10 [ RES_30_SEC, RES_1_MIN, RES_15_MIN, RES_1_HOUR, RES_1_DAY, RES_1_MONTH, RES_1_YEAR, RES_5_MIN, RES_200_MIL, RES_500_MIL, RES_1_SEC ]\n- fuente (int): [0 -->RAW, 1 -->STATS_PER_HOUR, 2 -->STATS_PER_DAY, 3 -->STATS_PER_MONTH, 4 -->TRANSIENT]\n\nReturns:\n- filtered_hist (dataframe). Dataframe con los campos [index, timeStamp, name, value, uid]\n\nEjemplo:\n\n```\n# Lectura de loe metadatos de todos los tags contenidos en la API (necesario)\ndatos = self.NX.callGetTags()\ncolumnas = json_normalize(datos)\n\n# Profundidad del análisis en fechas desde hoy\ndelta_days = 3\ndate_to = datetime.datetime.now()\ndate_from = date_to - datetime.timedelta(days=delta_days)\n\nfiltered_hist = NX.filter_installation(date_from, date_to, columnas, resolucion=4)\n```\nSi quisiéramos filtrar las variables por texto o uids:\n```\n# Por uids:\nuids = [\'abc1\', \'abc2\', ...]\nfiltered_hist = NX.filter_installation(date_from, date_to, columnas, uids=uids, resolucion=4)\n# Por texto:\nfiltros = [\'var1\', \'var2\', ...]\nfiltered_hist = NX.filter_installation(date_from, date_to, columnas, filter_txt=filtros, resolucion=4)\n```\n\n### filter_tagview\n\nLa funcion recibe como parametros la fecha ini, fecha fin, un df con los uid y\nlos nombres de las variables de la instalación y el filtro de texto aplicar (pueden ser varios)\n\nArgs:\n- Datefrom (datetime)\n- Dateto (datetime)\n- columnas (dataframe)\n- filter_txt (optional: list or str)\n- resolucion (int): de 0 a 10 [ RES_30_SEC, RES_1_MIN, RES_15_MIN, RES_1_HOUR, RES_1_DAY, RES_1_MONTH, RES_1_YEAR, RES_5_MIN, RES_200_MIL, RES_500_MIL, RES_1_SEC ]\n- fuente (int): [0 -->RAW, 1 -->STATS_PER_HOUR, 2 -->STATS_PER_DAY, 3 -->STATS_PER_MONTH, 4 -->TRANSIENT]\n\nReturns:\n- filtered_hist (dataframe). Dataframe con los campos [index, timeStamp, name, value, uid]\n\nExactamente igual que la anterior pero aplicable a vistas de variables (recomendado)\n\nPrimero hay que especificar el uid de la vista de variables deseada. Puede obtenerse desde Nexus o obtenerse a través de métodos de la API\n```\n# Leer vistas de variables asociadas al token  \ntagviews = NX.callGetDocuments()  \ntagviews = json_normalize(tagviews)  \n# Busqueda del uid de la vista\nuid_tagview = tagviews.uid[0]\n```\nSe especifica la ventana temporal deseada:\n```\n# Profundidad del análisis en fechas desde hoy  \ndelta_days = xxx  \ndate_format = \'%m/%d/%Y %H:%M:%S %Z\'  \ndate_to = datetime.datetime.now()  \ndate_from = date_to - datetime.timedelta(days=delta_days)\n```\nHay que especificar las variables deseadas de la vista de variables elegida. Con este código se obtienen todos los uids de las variables de la vista.\n```\n# Variables en la vista de variables  \nvbles = NX.callGetTagViews(uid_tagview)  \ndf = pd.DataFrame(vbles)  \ncolumnas = df[\'columns\']  \ncolumnas = json_normalize(columnas)  \n```\nFinalmente se obtiene el histórico llamando a la función:\n```\nfiltered_hist = NX.filter_tagview(date_from, date_to, columnas, uid_tagview)\n```\nTambién puede filtrarse por texto o uid dentro de la vista\n```\n# Por uids:\nuids = [\'abc1\', \'abc2\', ...]\nfiltered_hist = NX.filter_tagview(date_from, date_to, columnas, uid_vista, uids=uids, resolucion=4)\n# Por texto:\nfiltros = [\'var1\', \'var2\', ...]\nfiltered_hist = NX.filter_tagview(date_from, date_to, columnas, uid_vista, filter_txt=filtros, resolucion=4)\n```\n\n\n### Subida de datos <a class="anchor" id="subida"></a>\n\nLos datos que se suban a través de la API se encontrarán en la instalación habilitada para el token.\n\nEn primer lugar hay que asegurarse de crear las variables necesarias. Este paso puede omitirse si ya han sido creadas:\n\n### callPostTagInsert\nConsulta de tags con permisos de escritura. Si la variable no existe se crea\n\nArgs:\n- variable_name(str): nombre de la variable a consultar o crear\n\n### callPostValueHist\n\nFunción de escritura de variables en histórico.\n\nArgs:\n- df_value_timestamp: dataframe con las variables y sus valores y timestamp\n\nEjemplo:\n\nUna vez creadas las variables, pueden insertarse datos tanto en histórico como en tiempo real.\n**Importante**: para subir los datos se requiere un dataframe con la siguiente estructura:\n\n| timeStamp      \t| name      \t| value          \t|\n|----------------\t|-----------\t|----------------\t|\n| epoch time (s) \t| variable1 \t| valor numérico \t|\n| epoch time (s) \t| variable2 \t| valor numérico \t|\n\n```\ntest_df = pd.DataFrame({\'timeStamp\': [time.time()], \'name\': [\'api_test\'], \'value\': [1]})\nNX.callPostValueHist(test_df)\n```\n\nEl método acepta datetime64[ns] pero se recomienda pasar primero a epoch time. Para pasar de fecha en datetime a epoch se puede usar:\n```\ndf[\'timeStamp\'] = df[\'timeStamp\'].apply(lambda x: x.timestamp())\n```\n\n### callPostValueRTmult\nEscritura de variable en tiempo real.\n\nArgs:\n- df_variable_name_value: dataframe con las variables y valores a escribir\n\nEjemplo:\n```\ntest_df = pd.DataFrame({\'timeStamp\': [time.time()], \'name\': [\'api_test\'], \'value\': [1]})\nNX.callPostValueRTmult(test_df)\n```\nRealmente la columna timeStamp no es necesaria en este caso, pero se recomienda mantener la estructura común al resto de métodos\n\n### callPostValue_operate(self, variable_uid, variable_value)\nEscritura de variable sobre PLC\n\nArgs:\n- variable_uid: nombre de la variable a escribir en el PLC\n- variable_value: valor de la variable a escribir\n\n### Uso de alarmas <a class="anchor" id="alarmas"></a>\nDesde la versión **0.4** del encapsulado pueden modificarse alarmas en la API. Para ello se debe obtener el uid de la alarma a modificar y luego llamar a la función:\n#### Obtener uids de alarmas del token\n```\nalarmas = NX.callGetAlarms()\n```\n\n#### Obtener información de alarma por uid\n```\nalarma = NX.callGetAlarmByuid(uid)\n```\n\n#### Obtener uids de alarmas por nombres. Puede usarse una lista de nombres o un string con un nombre\n```\nuids_alarmas = NX.get_alarms_uids_by_names([names])\n```\n#### Obtener uids de alarmas por grupos de alarmas. Puede usarse una lista de grupos o un string con un grupo\n```\nuids_grupo = NX.get_alarms_uids_by_groups([groups])\n```\n\n#### Cambiar el estado de la alarma. Debe especificarse el uid de la alarma y el estado a cambiar (\'ARE\' o \'EXR\')\n```\nNX.callPostAckAlarm(uid, estado)\n```\n\n#### Cambiar el mensaje de estado de la alarma\n```\nNX.callPostAlarmEvent(uid, msg)\n```\n\n### Email Alerts <a class="anchor" id="email"></a>\nDesde la versión **0.5** se añade soporte para generar alarmas de correo eléctronico.\n\nPara usar la función debe crearse un objeto de tipo EmailAlerts. Deben proporcionarse los parámetros de conexión.\n```\nclass EmailAlerts:\n    """\n    Email management\n    Attributes:\n        attachments: list of files to add to message. See add_attachment for individual files\n        environment: name of the environment (used to identify application)\n        message: email\'s body\n        subject: email\'s subject\n        smtp_address: configuration parameter\n        email_password: password\n        email_port: port of server\n        email_sender: snder address\n        email_receiver: receiver address\n        cooldown (optional): time in hours to wait between two emails\n    """\n```\nSe recomienda usar variables de entorno para proteger las credenciales. En caso de no estar definidas se deben especificar (reemplazar las líneas de os.getenv()):\n\n```\nimport os\n\nsmtp_address = \'outlook.office365.com\'\nsmtp_port = 587\n# Tiempo en horas entre envíos sucesivos\ncooldown = 1\n\n# datos de la cuenta de envio\nsender_email_address = os.getenv("SENDER_EMAIL_ADDRESS")\nemail_password = os.getenv("EMAIL_PASSWORD")\nreceiver_email_address = os.getenv("RECEIVER_EMAIL_ADDRESS")\n\nemail_alerts = EmailAlerts(smtp_address, smtp_port, sender_email_address, email_password, receiver_email_address, cooldown=cooldown)\n```\n\nUna vez creado el objeto email_alerts puede usarse con libertad, bien con los parámetros predeterminados o moficiando los componentes del mensaje\n\nEl asunto y el cuerpo del mensaje tienen valores predeterminados en función del nombre del archivo, pero environment es una variable requerida con la que identificar el entorno de producción.\n```\nenviroment = \'NEXUS_PROD\'\nsubject = \'ALARMA\'\nbody = \'Alarma de \' + environment\n\nemail_alerts.set_email_alert_info(subject, body, environment)\n```\n\n\nSe puede usar la alerta de correo en cualquier función, sea de la API o no. Si la ejecución falla, \nse captura la excepción y se envía un correo con el error (mensaje predeterminado).\n\nSi se quiere incorporar a un script entero, debe usarse la función main()\n\n```\n# Uso del decorador para generar el correo\n\n@email_alerts.email_alert_decorator\ndef main():\n    # Aquí va todo el código del programa...\n    raise Exception(\'Error en la función\')\n    \nif __name__ == \'__main__\':\n    main() # Si aparece un error, se envía un correo con el error\n```\n\n## Contribuir <a class="anchor" id="contribuir"></a>\n\nCualquier función o sugerencia añadida es bien recibida.\n\nSugerencias:\n\n- Traducir documentación\n\n## Change log <a class="anchor" id="changelog"></a>\n\n###v0.9.0 - 15/02/2023\n**Added**\n- Operate method to write directly into PLC variables\n- NexusAPI custom exception\n- logging options\n\n###v0.8.0 - 04/11/2022\n**Added**\n- Support for cooldown options in email_alerts: pass time in hours as cooldown parameter in EmailAlerts\nclass to avoid sending more than 1 email in a given time\n\n###v0.7.0 - 20/09/2022\n**Important**\nThis update changes data structure of filter_tagview and filter_installation response. Please check your code before updating\n\n\n**Added**\n  - filter_tagview and filter_installation search by uid support\n  - filter_tagview and filter_installation match structure (index, uid, name, value, timeStamp (datetime))\n\n**Fix**\n  - Now filter_installation and filter_tagview will raise an error if API response is not valid\n\n**Updated**\n  - Better docs\n\n###v0.6.2 - 09/09/2022\n**Updated**\n- Better docs\n\n**Fix**\n- Now filter_installation/tagview raises an exception if dataframe structure is not correct\n\n###v0.6.0 - 10/05/2022\n**Added**\n- Email attachments\n\n###v0.5.0 - 12/04/2022\n\n**Added**\n\n - Email alerts functions\n\n**Changed**\n\n - Documentation\n\n###v0.4.0 - 30/03/2022\n\n**Added**\n  \n- API V2 alarm functions\n  * callPostAckAlarm(uid, status)\n  * callPostAlarmEvent(uid, msg)\n  * callGetAlarms()\n  * callGetAlarmByuid(uid)\n  * get_alarms_uids_by_names([names])\n  * get_alarms_uids_by_groups([groups])\n- Unit tests\n- .env file in order protect credentials\n- Bypassed 50k row limit in POST methods\n- Added support to datetime objects in callPostValueHist\n  \n**Modified**\n  \n- Unified callPostValueHist and callPostValueHistmult (deprecated)\n  \n###v0.3.2 - 11/03/2022\n**Added**\n- Add filter_installation and filter_tagview as replacement for GetFiltered\n- Add README.md\n\n## Contacto <a class="anchor" id="chapter6"></a>\n[**Pau Juan**](mailto:pau.juan@nexusintegra.io)\n*Operaciones*\n\n\n[**Laura Moreno**](mailto:laura.moreno@nexusintegra.io)\n*Operaciones*\n\n\n[**Ricardo Gómez**](mailto:ricardo.gomez.aldaravi@nexusintegra.io)\n*Operaciones*\n\n[Nexus Integra](https://nexusintegra.io/)\n',
    'author': 'Nexus Integra',
    'author_email': 'None',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'https://nexusintegra.io',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.11,<4.0',
}


setup(**setup_kwargs)
