{"id":50604561,"url":"https://github.com/pedrozavalat/echo-lib","last_synced_at":"2026-06-05T21:30:33.842Z","repository":{"id":288358159,"uuid":"967778547","full_name":"pedrozavalat/echo-lib","owner":"pedrozavalat","description":"API Client library for ECHO Home Assistant Integration","archived":false,"fork":false,"pushed_at":"2026-05-23T03:57:52.000Z","size":484,"stargazers_count":0,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-23T05:25:24.202Z","etag":null,"topics":["api-rest","clean-architecture","ftp-client","iot","puc","sharepoint"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pedrozavalat.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-17T01:46:25.000Z","updated_at":"2026-05-07T23:08:27.000Z","dependencies_parsed_at":"2025-04-17T15:30:02.251Z","dependency_job_id":"6927e591-0105-4712-82ed-6f1a35bc1d77","html_url":"https://github.com/pedrozavalat/echo-lib","commit_stats":null,"previous_names":["pedrozavalat/rcer_iot_client_pkg","pedrozavalat/saviia-lib","pedrozavalat/echo-lib"],"tags_count":60,"template":false,"template_full_name":null,"purl":"pkg:github/pedrozavalat/echo-lib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrozavalat%2Fecho-lib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrozavalat%2Fecho-lib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrozavalat%2Fecho-lib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrozavalat%2Fecho-lib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pedrozavalat","download_url":"https://codeload.github.com/pedrozavalat/echo-lib/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pedrozavalat%2Fecho-lib/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33961252,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-rest","clean-architecture","ftp-client","iot","puc","sharepoint"],"created_at":"2026-06-05T21:30:32.000Z","updated_at":"2026-06-05T21:30:33.836Z","avatar_url":"https://github.com/pedrozavalat.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ECHO Library \n\u003e Edge Computing \u0026 Hardware Orchestration API library for Home Assistant. \n\n\n\n[![GitHub release (latest by date)](https://img.shields.io/github/v/release/pedrozavalat/saviia-lib?style=for-the-badge)](https://github.com/pedrozavalat/saviia-lib/releases)\n\n\n## Table of Contents\n- [Installation](#installation)\n- [ECHO API Client Usage](#echo-api-client-usage)\n     - [Initialize the ECHO API Client](#initialize-the-echo-api-client)\n        - [Access THIES Data Logger Services](#access-thies-data-logger-services)\n            - [THIES files extraction and synchronization](#thies-files-extraction-and-synchronization)\n            - [Get THIES status](#get-thies-status)\n            - [Post THIES precomputed actions](#post-thies-precomputed-actions)\n            - [Detect Failures](#detect-failures)\n        \n        - [Access Backup Services](#access-backup-services)\n            - [Create Backup](#create-backup)\n            - [Export Files](#export-files)\n        - [Access Netcamera Services](#access-netcamera-services)\n            - [Get Camera Rates](#get-camera-rates)\n        - [Access Task System Services](#access-task-system-services)\n            - [Create Task](#create-task)\n            - [Update Task](#update-task)\n            - [Delete Task](#delete-task)\n            - [Get Tasks](#get-tasks)\n- [Related Projects](#related-projects)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\nThis library is designed for use with the SAVIIA Home Assistant Integration. It provides an API to retrieve files from a THIES Data Logger via an FTP server and upload them to a Microsoft SharePoint folder using the SharePoint REST API.\n\n```bash\npip install saviialib\n```\n\n## ECHO API Client Usage\n\n### Initialize the ECHO API Client\nImport the necessary classes from the library.\n```python\nfrom saviialib import SaviiaAPI, SaviiaAPIConfig\n```\n\nTo start using the library, you need to create an `SaviiaAPI` client instance with its configuration class `SaviiaAPIConfig`. Provide the required parameters such as FTP server details and SharePoint credentials:\n```python\nconfig = SaviiaAPIConfig(\n    ftp_port=FTP_PORT,\n    ftp_host=FTP_HOST,\n    ftp_user=FTP_USER,\n    ftp_password=FTP_PASSWORD,\n    sharepoint_client_id=SHAREPOINT_CLIENT_ID,\n    sharepoint_client_secret=SHAREPOINT_CLIENT_SECRET,\n    sharepoint_tenant_id=SHAREPOINT_TENANT_ID,\n    sharepoint_tenant_name=SHAREPOINT_TENANT_NAME,\n    sharepoint_site_name=SHAREPOINT_SITE_NAME\n)\n```\n```python\napi_client = SaviiaAPI(config)\n```\n**Notes:** \n- Store sensitive data like `FTP_PASSWORD`, `FTP_USER`, and SharePoint credentials securely. Use environment variables or a secrets management tool to avoid hardcoding sensitive information in your codebase.\n\n### Access THIES Data Logger Services\nTo interact with the THIES Data Logger services, you can access the `thies` attribute of the `SaviiaAPI` instance:\n```python\nthies_service = api_client.get('thies')\n```\nThis instance provides methods to interact with the THIES Data Logger. Currently, it includes the main method for extracting files from the FTP server and uploading them to SharePoint.\n\n#### THIES files extraction and synchronization\nThe library provides a method to extract and synchronize THIES Data Logger files with the Microsoft SharePoint client. This method downloads files from the FTP server and uploads them to the specified SharePoint folder:\n```python \nimport asyncio\nasync def main():\n    # Before calling this method, you must have initialised the THIES service class ...\n    response = await thies_service.update_thies_data()\n    return response\n\nasyncio.run(main())\n```\n\n##### Get THIES status\nYou can check whether THIES data needs syncing or backup by calling `get_thies_data` with FTP credentials and a SharePoint destination path:\n\n```python\nimport asyncio\n\nasync def main():\n    response = await thies_service.get_thies_data(\n        ftp_port=21,\n        ftp_host=\"ftp.example.com\",\n        ftp_user=\"anonymous\",\n        ftp_password=\"\",\n        sharepoint_destination_path=\"Shared%20Documents/General/Test_Raspberry/THIES/AVG\",\n    )\n    return response\n\nasyncio.run(main())\n```\n\n##### Post THIES precomputed actions\nIf you already computed whether to sync or backup externally, call `post_thies_data` to execute the actions:\n\n```python\nimport asyncio\n\nasync def main():\n    response = await thies_service.post_thies_data(\n        ftp_port=21,\n        ftp_host=\"ftp.example.com\",\n        ftp_user=\"anonymous\",\n        ftp_password=\"\",\n        need_to_sync=True,\n        need_to_backup=False,\n        sharepoint_destination_path=\"Shared%20Documents/General/Test_Raspberry/THIES/AVG\",\n        ftp_server_folders_path=[\"/ARCH_AV1\", \"/ARCH_EX1\"],\n        local_backup_source_path=\"saviia-local-backup\",\n    )\n    return response\n\nasyncio.run(main())\n```\n\nThe `need_to_backup` allows you to trigger a backup of the THIES files in a local folder, while `need_to_sync` will trigger the synchronization of THIES files between the Local Backup and SharePoint. You can set either or both to `True` depending on your needs.\n\n##### Detect Failures\nUse `detect_failures` to scan a local backup folder for missing or corrupt THIES files over the last N days. \n\n```python\nimport asyncio\n\nasync def main():\n    response = await thies_service.detect_failures(\n        local_backup_source_path=\"saviia-local-backup\",\n        n_days=7\n    )\n    return response\n\nasyncio.run(main())\n```\n\n### Access Backup Services\nTo interact with the Backup services, you can access the `backup` attribute of the `SaviiaAPI` instance:\n```python\nbackup_service = api_client.get('backup')\n```\nThis instance provides methods to interact with the Backup services. Currently, it includes the main method for creating backups of specified directories in a local folder from Home Assistant environment. Then each backup file is uploaded to a Microsoft SharePoint folder.\n\n#### Create Backup\nThe library provides a method which creates a backup of a specified directory in a local folder from Home Assistant environment. Then each backup file is uploaded to a Microsoft SharePoint folder: \n\n```python\nimport asyncio\nasync def main():\n    # Before calling this method, you must have initialised the Backup service class ...\n    response = await backup_service.upload_backup_to_sharepoint(\n        local_backup_path=LOCAL_BACKUP_PATH,\n        sharepoint_folder_path=SHAREPOINT_FOLDER_PATH\n    )\n    return response\nasyncio.run(main())\n```\n**Notes:**\n- Ensure that the `local_backup_path` exists and contains the files you want to back up. It is a relative path from the Home Assistant configuration directory.\n- The `sharepoint_folder_path` should be the path to the folder in SharePoint where you want to upload the backup files. For example, if your url is `https://yourtenant.sharepoint.com/sites/yoursite/Shared Documents/Backups`, the folder path would be `sites/yoursite/Shared Documents/Backups`.\n\n#### Export Files\nUse `export_files` to synchronize a local folder (under the configured backup root) with a specific SharePoint destination. This method validates the local folder, compares local files with SharePoint (existence and file size) and uploads only the missing or size-different files.\n\nExample usage:\n```python\nimport asyncio\n\nasync def main():\n    # backup_service was obtained from SaviiaAPI as shown above\n    # `local_folder_path` is a relative path under your configured local backup root,\n    # for example: \"thies/AVG\"\n    response = await backup_service.export_files(\n        local_folder_path=\"thies/AVG\",\n        sharepoint_destination_path=\"Shared%20Documents/General/Test_Raspberry/saviia-local-backup/thies/AVG\"\n    )\n    return response\n\nasyncio.run(main())\n```\n\nNotes:\n- `local_folder_path`: relative folder under your configured `local_backup_path` where files are read from.\n- `sharepoint_destination_path`: the exact destination folder in SharePoint where files will be created/uploaded. The controller will add the server-relative prefix (e.g. `/sites/{site_name}`) when required.\n- The controller is responsible for instantiating the external clients (SharePoint, file reader, directory client); the use case only contains orchestration and business logic.\n- If SharePoint reports a file size of zero for a remote item, the code treats that as \"unknown\" and will not force a resync based solely on a zero-length remote size. Only files that are missing in SharePoint or that have differing non-zero sizes will be uploaded.\n\n### Access Netcamera Services\nThe Netcamera service provides camera capture rate configuration based on meteorological data such as precipitation and precipitation probability.\n\nThis service uses the Weather Client library, currently implemented with OpenMeteo, and is designed to be extensible for future weather providers.\n\n```python \nnetcamera_service = api_client.get(\"netcamera\")\n```\n#### Get Camera Rates\nReturns photo and video capture rates for a camera installed at a given geographic location.\n```python \nimport asyncio\n\nasync def main():\n    lat, lon = 10.511223, 20.123123\n    camera_rates = await netcamera_service.get_camera_rates(latitude=lat, longitude=lon)\n    return camera_rates\nasyncio.run(main())\n```\nExample output:\n```python \n{\n    \"status\": \"A\",          # B or C\n    \"photo_rate\": number,   # in minutes\n    \"video_rate\": number    # in minutes\n}\n```\n#### Description:\n* The capture rate is calculated using meteorological metrics:\n    * Precipitation\n    * Precipitation probability\n* The resulting configuration determines the camera capture frequency.\n\n#### Status variable\nThe status variable is classified based on weather conditions (currently, precipitation and precipitation probability) at the camera's location:\n\n| Status | 1 photo capture per | 1 video capture per |\n| --- | --- | --- |\n| A | 12 h | 12 h |\n| B | 30 min | 3 h |\n| C | 5 min | 1 h |\n\n\n### Access Task System Services\nTo interact with the Task System services, you can access the `tasks` attribute of the `SaviiaAPI` instance:\n```python\ntasks_service = api_client.get('tasks')\n```\nThis instance provides methods to manage tasks in specified channels. Note that this service requires an existing bot to be set up in the Discord server to function properly.\n\nFor using the Tasks Services, you need to provide the additional parameters `bot_token` and `task_channel_id` in the `SaviiaAPIConfig` configuration class:\n\n```python\nconfig = SaviiaAPIConfig(\n    ... \n    task_channel_id=TASK_CHANNEL_ID,\n    bot_token=BOT_TOKEN\n)\n```\nThe `task_channel_id` is the ID of the Discord channel where tasks will be created, updated, and deleted. The `bot_token` is the token of the Discord bot that has permissions to manage messages in that channel.\n\n\n#### Create Task\nCreate a new task in a Discord channel with the following properties:\n```python\nimport asyncio\n\nasync def main():\n    response = await tasks_service.create_task(\n        task={\n            \"name\": \"Task Title\",\n            \"description\": \"Task Description\",\n            \"due_date\": \"2024-12-31T23:59:59Z\",\n            \"priority\": 1,\n            \"assignee\": \"user_name\",\n            \"category\": \"work\",\n        },\n         images=[\n            {\n                \"name\": \"image.png\",\n                \"type\": \"image/png\",\n                \"data\": \"base64_encoded_data\"\n            }\n        ],\n        config=config\n    )\n    return response\n\nasyncio.run(main())\n```\n**Notes:**\n- `name`, `description`, `due_date`, `priority`, `assignee`, and `category` are required.\n- `images` is optional and accepts up to 10 images.\n- `due_date` must be in ISO 8601 format (datetime).\n- `priority` must be an integer between 1 and 4.\n\n#### Update Task\nUpdate an existing task or mark it as completed. The task will be reacted with ✅ if completed or 📌 if pending:\n```python\nimport asyncio\n\nasync def main():\n    response = await tasks_service.update_task(\n        task={\n            \"id\": \"task_id\",\n            \"name\": \"Updated Title\",\n            \"description\": \"Updated Description\",\n            \"due_date\": \"2024-12-31T23:59:59Z\",\n            \"priority\": 2,\n            \"assignee\": \"updated_user_name\",\n            \"category\": \"work\"\n        }, # Must contain all the attributes of the task\n        completed=True,\n        config=config\n    )\n    return response\n\nasyncio.run(main())\n```\n\n\n#### Delete Task\nDelete an existing task from a Discord channel by providing its ID:\n```python\nimport asyncio\n\nasync def main():\n    response = await tasks_service.delete_task(\n        task_id=\"task_id\",\n        config=config\n    )\n    return response\n\nasyncio.run(main())\n```\n\n#### Get Tasks\nRetrieve tasks from a Discord channel with optional filtering and sorting:\n```python\nimport asyncio\n\nasync def main():\n    response = await tasks_service.get_tasks(\n        params={\n            \"sort\": \"desc\",\n            \"completed\": False,\n            \"fields\": [\"title\", \"due_date\", \"priority\"],\n            \"after\": 1000000,\n            \"before\": 2000000\n        },\n        config=config\n    )\n    return response\n\nasyncio.run(main())\n```\n**Notes:**\n- `sort`: Order results by `asc` or `desc`.\n- `completed`: Filter tasks by completion status.\n- `fields`: Specify which fields to include in the response. Must include `title` and `due_date`.\n- `after` and `before`: Filter tasks by timestamp ranges.\n\n#### Get Pending Tasks\nTo retrieve pending (uncompleted) tasks and optionally download attachments or trigger notifications, call `get_pending_tasks`:\n\n```python\nimport asyncio\n\nasync def main():\n    # download: if True, attachments for pending tasks will be downloaded\n    # notify: if True, the configured bot will send notifications for pending tasks\n    response = await tasks_service.get_pending_tasks(download=False, notify=False)\n    return response\n\nasyncio.run(main())\n```\nThe notifications are sent as messages in the configured Discord channel, mentioning the assignee of each pending task with its title and due date.\n\n\n\n## Contributing\nIf you're interested in contributing to this project, please follow the contributing guidelines. By contributing to this project, you agree to abide by its terms.\nContributions are welcome and appreciated!\n\n## Related Projects\n* [ECHO](https://github.com/raxlab/echo): A Home Assistant custom integration for Edge Computing and Hardware Orchestration that uses this library.\n\n## License\n\n`saviialib` was created by Pedro Pablo Zavala Tejos. It is licensed under the terms of the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrozavalat%2Fecho-lib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpedrozavalat%2Fecho-lib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrozavalat%2Fecho-lib/lists"}