diff --git a/docs/source/Resources/Dashboards/Dashboard_Type.rst b/docs/source/Resources/Dashboards/Dashboard_Type.rst
index a605f54..ad8fa48 100644
--- a/docs/source/Resources/Dashboards/Dashboard_Type.rst
+++ b/docs/source/Resources/Dashboards/Dashboard_Type.rst
@@ -1,295 +1,529 @@
-**Dashboards Type**
-====================
+**Dashboard Type**
+==================
.. _Arrangement:
Arrangement
-------------
+-----------
+
+ Widget arrangement configuration on the dashboard layout.
**Attributes:**
| **widget_id**: str
+ | Unique identifier for the widget
+
| **x**: int or float
+ | Horizontal position coordinate
+
| **y**: int or float
+ | Vertical position coordinate
+
| **width**: int or float
+ | Widget width
+
| **height**: int or float
+ | Widget height
+
| **tab**: Optional[str]
+ | Tab identifier where the widget is located
.. _DashboardCreateInfo:
DashboardCreateInfo
---------------------
+-------------------
+
+ Information required to create a new dashboard.
**Attributes:**
- **label**: str
+ | **label**: str
+ | Dashboard label/name
+
+ | **arrangement**: list[:ref:`Arrangement`]
+ | Layout configuration for widgets
- **arrangement**: list[Arrangement]
+ | **tags**: list[:ref:`TagsObj`]
+ | Tags for dashboard categorization
- **tags**: list[:ref:`TagsObj`]
+ | **visible**: bool
+ | Dashboard visibility status
- **visible**: bool
.. _icon:
icon
------
+----
+
+ Dashboard icon configuration.
**Attributes:**
| **url**: str
+ | Icon URL
+
| **color**: Optional[str]
+ | Icon color Hexadecimal
+
.. _conditions:
conditions
------------
+----------
+
+ Condition key-value pair for blueprint device filtering.
**Attributes:**
| **key**: str
+ | Condition key
+
| **value**: str
+ | Condition value
+
.. _filter_conditions:
filter_conditions
-------------------
+-----------------
+
+ Filter conditions for blueprint device selection.
+
**Attributes:**
| **blueprint_device**: str
+ | Blueprint device identifier
+
| **tag_key**: str
+ | Tag key for filtering
+
| **type**: str
+ | Filter type
.. _shared:
shared
---------
+------
+
+ Dashboard sharing information.
**Attributes:**
| **id**: str
+ | Share identifier
+
| **email**: str
+ | Shared user email
+
| **name**: str
+ | Shared user name
+
| **free_account**: bool
+ | Whether the user has a free account
+
| **allow_tags**: bool
+ | Whether tags are allowed
+
| **expire_time**: str
+ | Share expiration time
+
| **allow_share**: bool
+ | Whether re-sharing is allowed
-.. _blueprint_devices_conditions:
-blueprint_devices
--------------------
+.. _BlueprintDeviceConfig:
+
+BlueprintDeviceConfig
+---------------------
+
+ Blueprint device configuration for dynamic dashboards.
**Attributes:**
- | **conditions**: list[conditions]
+ | **conditions**: list[:ref:`conditions`]
+ | Device selection conditions
+
| **name**: str
+ | Blueprint name
+
| **id**: str
+ | Blueprint identifier
+
| **label**: str
- | **filter_conditions**: list[filter_conditions]
+ | Blueprint label
+
+ | **filter_conditions**: list[:ref:`filter_conditions`]
+ | Filter conditions
+
| **theme**: any
+ | Theme configuration
+
| **setup**: any
+ | Setup configuration
+
.. _DashboardInfo:
DashboardInfo
----------------
+-------------
+
+ Complete dashboard information.
**Attributes:**
| **id**: :ref:`GenericID`
+ | Dashboard unique identifier
+
| **created_at**: datetime
+ | Dashboard creation timestamp
+
| **updated_at**: datetime
+ | Last update timestamp
+
| **last_access**: datetime
+ | Last access timestamp
+
| **group_by**: list
+ | Grouping configuration
+
| **tabs**: list
- | **icon**: icon
+ | Dashboard tabs
+
+ | **icon**: :ref:`icon`
+ | Dashboard icon
+
| **background**: any
+ | Background configuration
+
| **type**: str
+ | Dashboard type
+
| **blueprint_device_behavior**: "more_than_one" or "always"
+ | Blueprint device behavior mode
+
| **blueprint_selector_behavior**: "open" or "closed" or "always_open" or "always_closed"
- | **blueprint_devices**: blueprint_devices
+ | Blueprint selector behavior mode
+
+ | **blueprint_devices**: :ref:`BlueprintDeviceConfig`
+ | Blueprint device configuration
+
| **theme**: any
+ | Dashboard theme
+
| **setup**: any
- | **shared**: shared
+ | Dashboard setup
+
+ | **shared**: :ref:`shared`
+ | Sharing configuration
+
.. _WidgetData:
WidgetData
-------------
+----------
+
+ Widget data configuration.
**Attributes:**
- | **origin**: GenericID
- | **qty**: Optional[Union[int, float]]
+ | **origin**: :ref:`GenericID`
+ | Data origin identifier
+
+ | **qty**: Optional[int or float]
+ | Quantity of data points
+
| **timezone**: Optional[str]
+ | Timezone for data queries
+
| **variables**: Optional[str]
- | **bucket**: Optional[GenericID]
+ | Variables to query
+
+ | **bucket**: Optional[:ref:`GenericID`]
+ | Bucket identifier
+
| **query**: Optional["min" or "max" or "count" or "avg" or "sum"]
- | **start_date**: Optional[Union[datetime, str]]
- | **end_date**: Optional[Union[datetime, str]]
+ | Query type
+
+ | **start_date**: Optional[datetime or str]
+ | Query start date
+
+ | **end_date**: Optional[datetime or str]
+ | Query end date
+
| **overwrite**: Optional[bool]
+ | Whether to overwrite existing data
+
.. _WidgetResource:
WidgetResource
------------------
+--------------
+
+ Widget resource filtering configuration.
**Attributes:**
- filter: list[:ref:`TagsObj`]
+ | **filter**: list[:ref:`TagsObj`]
+ | Filter tags
+
.. _DeviceResourceView:
DeviceResourceView
--------------------
+------------------
+
+ Available views for device resources in widgets.
- | **view**: f"tags.{str}" or f"param.{str}" or "name" or "id" or "bucket_name" or "network_name" or "connector_name" or "connector" or "network" or "bucket" or "last_input" or "created_at" or "active"
+ **Type:**
+
+ | Literal[f"tags.{str}", f"param.{str}", "name", "id", "bucket_name", "network_name", "connector_name", "connector", "network", "bucket", "last_input", "created_at", "active"]
.. _WidgetDeviceResource:
WidgetDeviceResource
------------------------
+--------------------
+
+ Device resource configuration for widgets.
**Attributes:**
| **type**: "device"
- | **view**: DeviceResourceView
+ | Resource type
+
+ | **view**: :ref:`DeviceResourceView`
+ | View configuration
+
| **editable**: "name" or f"tags.{str}" or f"param.{str}"
+ | Editable fields
+
.. _EditDeviceResource:
EditDeviceResource
---------------------
+------------------
+
+ Device resource edit configuration.
**Attributes:**
- | **device**: GenericID
+ | **device**: :ref:`GenericID`
+ | Device identifier
+
| **name**: Optional[str]
+ | Device name
+
| **active**: Optional[bool]
- | **edit**: dict[str, Union[str, bool]]
+ | Device active status
+
+ | **edit**: dict[str, str or bool]
+ | Fields to edit
+
.. _EditResourceOptions:
EditResourceOptions
----------------------
+-------------------
+
+ Options for editing resources.
**Attributes:**
| **identifier**: Optional[str]
+ | Resource identifier
+
.. _WidgetInfo:
WidgetInfo
--------------
+----------
+
+ Complete widget information.
**Attributes:**
- | **analysis_run**: Optional[GenericID]
- | **dashboard**: Optional[GenericID]
+ | **analysis_run**: Optional[:ref:`GenericID`]
+ | Analysis run identifier
+
+ | **dashboard**: Optional[:ref:`GenericID`]
+ | Dashboard identifier
+
| **display**: any
- | **data**: Optional[list[WidgetData]]
- | **resource**: Optional[list[WidgetDeviceResource]]
- | **id**: Optional[GenericID]
+ | Display configuration
+
+ | **data**: Optional[list[:ref:`WidgetData`]]
+ | Widget data configuration
+
+ | **resource**: Optional[list[:ref:`WidgetDeviceResource`]]
+ | Widget resource configuration
+
+ | **id**: Optional[:ref:`GenericID`]
+ | Widget identifier
+
| **label**: str
+ | Widget label
+
| **realtime**: Optional[bool]
+ | Real-time update status
+
| **type**: str
+ | Widget type
+
.. _DevicesRelated:
DevicesRelated
----------------
+--------------
+
+ Device information related to dashboard.
+
+ Extends BucketDeviceInfo with additional bucket field.
**Attributes:**
- | **bucket**: GenericID
+ | **id**: :ref:`GenericID`
+ | Device identifier
+
+ | **name**: str
+ | Device name
+
+ | **bucket**: :ref:`GenericID`
+ | Bucket identifier
+
.. _AnalysisRelated:
AnalysisRelated
---------------
+ Analysis information related to dashboard.
+
**Attributes:**
- | **id**: GenericID
+ | **id**: :ref:`GenericID`
+ | Analysis identifier
+
| **name**: str
+ | Analysis name
+
.. _PostDataModel:
PostDataModel
---------------
+-------------
+
+ Model for posting data to widgets.
**Attributes:**
- | **origin**: GenericID
+ | **origin**: :ref:`GenericID`
+ | Data origin identifier
+
| **variable**: str
+ | Variable name
-.. _blueprint_devices_origin:
-blueprint_devices
--------------------
+.. _BlueprintDeviceOrigin:
+
+BlueprintDeviceOrigin
+---------------------
+
+ Blueprint device configuration with origin reference for widget data queries.
**Attributes:**
- | **origin**: GenericID
- | **id**: GenericID
- | **bucket**: Optional[GenericID]
+ | **origin**: :ref:`GenericID`
+ | Origin identifier
+
+ | **id**: :ref:`GenericID`
+ | Device identifier
+
+ | **bucket**: Optional[:ref:`GenericID`]
+ | Bucket identifier
+
.. _widgetOverwrite:
widgetOverwrite
-----------------
+---------------
+
+ Widget data overwrite options.
**Attributes:**
| **start_date**: Optional[any]
+ | Override start date
+
| **end_date**: Optional[any]
+ | Override end date
+
| **timezone**: Optional[any]
+ | Override timezone
+
.. _GetDataModel:
GetDataModel
--------------
+------------
+
+ Model for retrieving widget data.
**Attributes:**
- | **overwrite**: Optional[widgetOverwrite]
- | **blueprint_devices**: Optional[list[blueprint_devices]]
- | **page**: Optional[Union[int, float]]
- | **amount**: Optional[Union[int, float]]
+ | **overwrite**: Optional[:ref:`widgetOverwrite`]
+ | Overwrite options
+
+ | **blueprint_devices**: Optional[list[:ref:`BlueprintDeviceOrigin`]]
+ | Blueprint devices list
+
+ | **page**: Optional[int or float]
+ | Page number for pagination
+
+ | **amount**: Optional[int or float]
+ | Amount of items per page
+
.. _PublicKeyResponse:
PublicKeyResponse
--------------------
+-----------------
+
+ Response containing dashboard public access token.
**Attributes:**
- | **token**: GenericToken
- | **expire_time**: ExpireTimeOption
+ | **token**: :ref:`GenericToken`
+ | Public access token
+
+ | **expire_time**: :ref:`ExpireTimeOption`
+ | Token expiration time
+
.. _EditDataModel:
EditDataModel
---------------
-
- | **EditDataModel** = :ref:`PostDataModel` and {id: :ref:`GenericID`}
+-------------
+ Model for editing widget data.
-.. _PublicKeyResponseType:
+ **Extends:** :ref:`PostDataModel`
-PublicKeyResponse
-------------------
+ **Additional Attributes:**
- | **PublicKeyResponse** = PublicKeyResponse
+ | **id**: :ref:`GenericID`
+ | Data record identifier
.. _widgetOverwriteOptions:
widgetOverwriteOptions
------------------------
- | **widgetOverwriteOptions** = "start_date" or "end_date" or "timezone"
+----------------------
+
+ Available options for widget data override.
+
+ **Type:**
+
+ | Literal["start_date", "end_date", "timezone"]
\ No newline at end of file
diff --git a/docs/source/Resources/Dashboards/index.rst b/docs/source/Resources/Dashboards/index.rst
index 2f9bfb4..0fd7681 100644
--- a/docs/source/Resources/Dashboards/index.rst
+++ b/docs/source/Resources/Dashboards/index.rst
@@ -1,147 +1,748 @@
**Dashboards**
==============
-Manage dashboards in account.
+Manage dashboards in your application.
=============
listDashboard
=============
-Retrieves a list with all dashboards from the account.
+Lists all dashboards from your application with pagination support.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **queryObj**: :ref:`Query`
- | Default query parameters for retrieving the list of dashboards.
+ | *Optional* **queryObj**: :ref:`Query`
+ | Query parameters to filter and paginate the results.
+
+ .. code-block::
+ :caption: **Default queryObj:**
+
+ queryObj = {
+ "page": 1,
+ "fields": ["id", "name"],
+ "filter": {},
+ "amount": 20,
+ "orderBy": ["label", "asc"]
+ }
**Returns:**
- | **result**: list[:ref:`DashboardInfo`]
- | List of dashboard information.
+ | list[:ref:`DashboardInfo`]
+ | List of dashboard information objects.
-=======
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Access" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.listDashboard({
+ "page": 1,
+ "fields": ["id", "name"],
+ "amount": 10,
+ "orderBy": ["label", "asc"]
+ })
+ print(result) # [{'id': 'dashboard-id-123', 'label': 'My Dashboard', ...}, ...]
+
+
+======
create
-=======
+======
+
+Creates a new dashboard in your application.
-Gets information about the dashboard
+See: `Dashboard Overview `_
**Parameters:**
| **dashboardObj**: :ref:`DashboardCreateInfo`
- | Dashboard object
+ | Dashboard configuration object
-======
+ **Returns:**
+
+ | dict
+ | Object containing the created dashboard ID
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Create" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.create({
+ "label": "My Dashboard",
+ "tags": [{"key": "type", "value": "monitoring"}]
+ })
+ print(result) # {'dashboard': 'dashboard-id-123'}
+
+
+====
edit
-======
+====
+
+Modifies an existing dashboard's properties.
-Modify any property of the dashboards
+See: `Dashboard Overview `_
**Parameters:**
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
- | dashboardObj: :ref:`DashboardCreateInfo`
- | Dashboard Object with data to be replaced
+ | **dashboardObj**: dict[str, Any]
+ | Dictionary with properties to update
+
+ **Returns:**
+
+ | str
+ | Success message
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Edit" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.edit("dashboard-id-123", {
+ "label": "Updated Dashboard",
+ "active": False
+ })
+ print(result) # Successfully Updated
======
delete
======
-Deletes an dashboard from the account
+Deletes a dashboard from the application.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+ **Returns:**
-======
+ | str
+ | Success message
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Delete" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.delete("dashboard-id-123")
+ print(result) # Successfully Removed
+
+
+====
info
-======
+====
-Gets information about the dashboard
+Retrieves detailed information about a specific dashboard.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ **Returns:**
+
+ | :ref:`DashboardInfo`
+ | Complete dashboard information
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Access" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ dashboard_info = resources.dashboards.info("dashboard-id-123")
+ print(dashboard_info) # {'id': 'dashboard-id-123', 'label': 'My Dashboard', ...}
=========
duplicate
=========
-Duplicate the dashboard to your own account
+Creates a copy of an existing dashboard.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier to duplicate
- | dashboardObj: { "setup": Optional[any], "new_label": Optional[str] }
- | Dashboard Object with data of the duplicate dashboard
+ | *Optional* **dashboardObj**: dict
+ | Duplication options
+
+ .. code-block::
+ :caption: **dashboardObj options:**
+
+ dashboardObj = {
+ "setup": Optional[Any], # Custom setup configuration
+ "new_label": Optional[str] # Label for the duplicated dashboard
+ }
+
+ **Returns:**
+
+ | dict
+ | Object with dashboard_id and success message
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Duplicate" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.duplicate("dashboard-id-123", {
+ "new_label": "Copy of My Dashboard"
+ })
+ print(result) # {'dashboard_id': 'new-dashboard-id', 'message': 'Dashboard duplicated successfully'}
============
getPublicKey
============
-Generate a new public token for the dashboard
+Generates a new public access token for the dashboard.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
- | expireTime: :ref:`ExpireTimeOption` = "never"
- | Time when token will expire
+ | *Optional* **expireTime**: :ref:`ExpireTimeOption`
+ | Time when token will expire (default: "never")
+ **Returns:**
-===================
+ | :ref:`PublicKeyResponse`
+ | Object with public token and expiration time
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ public_key = resources.dashboards.getPublicKey("dashboard-id-123", "1day")
+ print(public_key) # {'token': 'token-id-123', 'expire_time': '2025-01-02T00:00:00.000Z'}
+
+
+==================
listDevicesRelated
-===================
+==================
-Get list of devices related with dashboard
+Lists all devices associated with the dashboard.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ **Returns:**
+
+ | list[:ref:`DevicesRelated`]
+ | List of devices related to the dashboard
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Related devices" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ devices = resources.dashboards.listDevicesRelated("dashboard-id-123")
+ print(devices) # [{'id': 'device-id-123', 'bucket': 'bucket-id'}, ...]
===================
listAnalysisRelated
===================
-Get list of analysis related with a dashboard
+Lists all analyses associated with a dashboard.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ **Returns:**
+
+ | list[:ref:`AnalysisRelated`]
+ | List of analyses related to the dashboard
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Related analysis" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ analyses = resources.dashboards.listAnalysisRelated("dashboard-id-123")
+ print(analyses) # [{'id': 'analysis-id-123', 'name': 'Analysis #1'}, ...]
=============================
runWidgetHeaderButtonAnalysis
=============================
-Runs an analysis located in a widget's header button
+Executes an analysis from a widget's header button.
+
+See: `Dashboard Overview `_
**Parameters:**
- | **analysisID**: GenericID: str
- | The id of the analysis to run
+ | **analysisID**: :ref:`GenericID`
+ | The ID of the analysis to run
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | The ID of the widget that contains the header button
+
+ | *Optional* **scope**: dict[str, Any]
+ | Data to send to the analysis (default: {})
+
+ **Returns:**
+
+ | str
+ | Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.runWidgetHeaderButtonAnalysis(
+ "analysis-id-123",
+ "dashboard-id-456",
+ "widget-id-789",
+ {"custom_data": "value"}
+ )
+ print(result) # Analysis executed successfully
+
+
+=======
+Widgets
+=======
+
+The Widgets class provides methods to manage dashboard widgets. Access it through ``resources.dashboards.widgets``.
+
+==============
+widgets.create
+==============
+
+Creates a new widget for a specified dashboard with the given configuration.
+
+**Note:** After created, the widget is not added into the dashboard arrangement. You must edit the dashboard to include it in the arrangement.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetObj**: :ref:`WidgetInfo`
+ | Widget configuration object
+
+ **Returns:**
+
+ | dict[str, :ref:`GenericID`]
+ | Object containing the created widget ID
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Create and Edit" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.create("dashboard-id-123", {
+ "data": [{
+ "origin": "origin-id-123",
+ "query": "last_value",
+ "variables": ["temperature"]
+ }],
+ "display": {
+ "show_units": True,
+ "show_variables": True,
+ "variables": [{
+ "origin": "origin-id-123",
+ "variable": "temperature"
+ }]
+ },
+ "label": "Temperature",
+ "type": "display",
+ })
+ print(result) # {'widget': 'widget-id-456'}
+
+ # To add the widget size to the dashboard
+ # Before running this, make sure doesn't have more widgets in the dashboard.
+ resources.dashboards.edit("dashboard-id-123", {
+ "arrangement": [{
+ "widget_id": result["widget"],
+ "width": 1,
+ "height": 2,
+ "minW": 1,
+ "minH": 2,
+ "x": 0,
+ "y": 0
+ }]
+ })
+
+
+============
+widgets.edit
+============
+
+Updates an existing widget's configuration on a dashboard.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ | **data**: dict
+ | Dictionary with widget properties to update
+
+ **Returns:**
+
+ | str
+ | Success message
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Edit" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.edit("dashboard-id-123", "widget-id-456", {
+ "label": "Updated Temperature",
+ })
+ print(result) # Successfully Updated
+
+
+==============
+widgets.delete
+==============
+
+Permanently removes a widget from a dashboard.
+
+**Note:** After deleted, the widget is not removed from the dashboard arrangement. You must edit the dashboard to remove it from the arrangement.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ **Returns:**
+
+ | str
+ | Success message
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Delete and Edit" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.delete("dashboard-id-123", "widget-id-456")
+ print(result) # Successfully Removed
+
+ # To remove sizes from all widgets from a dashboard
+ # Before running this, make sure doesn't have more widgets in the dashboard.
+ resources.dashboards.edit("dashboard-id-123", {"arrangement": []})
+
+
+============
+widgets.info
+============
+
+Retrieves detailed information about a specific widget.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ **Returns:**
+
+ | :ref:`WidgetInfo`
+ | Complete widget information
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Dashboard" / "Access" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.info("dashboard-id-123", "widget-id-456")
+ print(result) # {'id': 'widget-id-456', 'data': [{'query': 'last_value', ...}, ...], ...}
+
+
+===============
+widgets.getData
+===============
+
+Retrieves data or resource list for a specific widget based on the given parameters.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ | *Optional* **params**: :ref:`GetDataModel`
+ | Query parameters for data retrieval
+
+ **Returns:**
+
+ | object
+ | Widget data and configuration
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.getData("dashboard-id-123", "widget-id-456", {
+ "start_date": "2025-01-01",
+ "end_date": "2025-12-31",
+ "timezone": "UTC"
+ })
+ print(result) # {'widget': {'analysis_run': None, 'dashboard': '6791456f8b726c0009adccec', ...}, ...}
+
+
+================
+widgets.sendData
+================
+
+Sends new data values to be displayed in the widget.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ | **data**: :ref:`PostDataModel` or list[:ref:`PostDataModel`]
+ | Data to send to the widget
+
+ | *Optional* **bypassBucket**: bool
+ | Whether to bypass bucket validation (default: False)
+
+ **Returns:**
+
+ | object
+ | Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.sendData("dashboard-id-123", "widget-id-456", {
+ "origin": "origin-id-123",
+ "variable": "temperature",
+ "value": 25.5,
+ "unit": "C"
+ })
+ print(result) # ['1 Data Added']
+
+
+================
+widgets.editData
+================
+
+Updates existing data values for a specific widget.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ | **data**: :ref:`EditDataModel` or list[:ref:`EditDataModel`]
+ | Data to update
+
+ | *Optional* **bypassBucket**: bool
+ | Whether to bypass bucket validation (default: False)
+
+ **Returns:**
+
+ | object
+ | Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.editData("dashboard-id-123", "widget-id-456", {
+ "origin": "origin-id-123",
+ "id": "data-id-789",
+ "value": 25.5
+ })
+ print(result) # Device Data Updated
+
+
+==================
+widgets.deleteData
+==================
+
+Removes multiple data items from the widget by pairs of data ID and resource ID.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ | **idPairs**: list[str]
+ | List of data ID and resource ID pairs in format "data_id:resource_id"
+
+ **Returns:**
+
+ | str
+ | Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.deleteData(
+ "dashboard-id",
+ "widget-id",
+ [
+ "data_1-id:device_A-id",
+ "data_2-id:device_A-id",
+ "data_3-id:device_B-id",
+ ]
+ )
+ print(result) # Successfully Removed
+
+
+====================
+widgets.editResource
+====================
+
+Updates resource values associated with the widget.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ | **resourceData**: :ref:`EditDeviceResource` or list[:ref:`EditDeviceResource`]
+ | Resource data to update
+
+ | *Optional* **options**: :ref:`EditResourceOptions`
+ | Edit options
+
+ **Returns:**
+
+ | object
+ | Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.dashboards.widgets.editResource(
+ "dashboard-id-123",
+ "widget-id-456",
+ {
+ "device": "device-id-789",
+ "name": "Updated Device Name",
+ "active": True
+ },
+ {"identifier": "my-identifier"}
+ )
+ print(result) # Resource Updated
+
+
+=====================
+widgets.tokenGenerate
+=====================
+
+Generates a new authentication token for embedding a widget. Each call regenerates the token.
+
+See: `Dashboard Overview `_ | `Widgets `_
+
+ **Parameters:**
+
+ | **dashboardID**: :ref:`GenericID`
+ | Dashboard identifier
+
+ | **widgetID**: :ref:`GenericID`
+ | Widget identifier
+
+ **Returns:**
+
+ | dict[str, :ref:`GenericToken`]
+ | Object containing the widget token
+
+ .. code-block:: python
- | **dashboardID**: GenericID: str
- | Dashboard identification
+ from tagoio_sdk import Resources
- | **widgetID**: GenericID: str
- | The id of the widget that contains the header button
+ resources = Resources()
+ result = resources.dashboards.widgets.tokenGenerate("dashboard-id-123", "widget-id-456")
+ print(result) # {'widget_token': 'widget-token-123'}
- | **scope**: Optional[any]
- | Data to send to the analysis
.. toctree::
diff --git a/docs/source/Resources/Devices/Devices_Type.rst b/docs/source/Resources/Devices/Devices_Type.rst
index adc54c3..2b2f5d8 100644
--- a/docs/source/Resources/Devices/Devices_Type.rst
+++ b/docs/source/Resources/Devices/Devices_Type.rst
@@ -485,3 +485,77 @@ ListDeviceTokenQuery
]]
| [Optional] Tuple with a field and an order
+
+.. _DeviceChunkData:
+
+DeviceChunkData
+---------------
+
+ Chunk information from an immutable device.
+
+ **Attributes:**
+
+ | **id**: str
+ | Chunk ID in format 'from_to' (Unix timestamps).
+
+ | **from_date**: str
+ | Start date of the chunk (ISO 8601).
+
+ | **to_date**: str
+ | End date of the chunk (ISO 8601).
+
+ | **amount**: int or float
+ | Amount of data records in the chunk.
+
+
+.. _DeviceDataBackup:
+
+DeviceDataBackup
+----------------
+
+ Parameters for device data backup operation.
+
+ **Attributes:**
+
+ | **deviceID**: :ref:`GenericID`
+ | Device ID.
+
+ | **file_address**: str
+ | File path in TagoIO Files where backup will be saved.
+ | Can use template variables: $DEVICE$, $CHUNK$, $FROM$, $TO$, $TIMESTAMP$.
+
+ | **headers**: Optional[bool]
+ | [Optional] Include CSV headers in the exported file.
+
+
+.. _DeviceDataBackupResponse:
+
+DeviceDataBackupResponse
+------------------------
+
+ Response from device data backup operation.
+
+ **Attributes:**
+
+ | **file_address**: str
+ | Final file path where the backup was saved.
+
+ | **chunk_id**: Optional[str]
+ | [Optional] Chunk ID if backup was for a specific chunk.
+
+
+.. _DeviceDataRestore:
+
+DeviceDataRestore
+-----------------
+
+ Parameters for device data restore operation.
+
+ **Attributes:**
+
+ | **deviceID**: :ref:`GenericID`
+ | Device ID.
+
+ | **file_address**: str
+ | File path in TagoIO Files to restore data from (CSV format).
+
diff --git a/docs/source/Resources/Devices/index.rst b/docs/source/Resources/Devices/index.rst
index 996834b..cf019d5 100644
--- a/docs/source/Resources/Devices/index.rst
+++ b/docs/source/Resources/Devices/index.rst
@@ -3,283 +3,699 @@
Manage devices in account.
-=======
+======
+amount
+======
+
+Gets the amount of data stored in a device.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ **Parameters:**
+
+ | **deviceID**: :ref:`GenericID`
+ | Device ID
+
+ **Returns:**
+
+ Union[int, float]
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ amount = resources.devices.amount("device-id-123")
+ print(amount) # 15234
+
+
+======
create
-=======
+======
+
+Creates a new device in the account with specified configuration and returns device credentials.
+
+ **See:**
-Generates and retrieves a new action from the Device
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
+ https://help.tago.io/portal/en/kb/articles/481-device-types Device Types
**Parameters:**
| **deviceObj**: :ref:`DeviceCreateInfo`
| Object data to create new device
+ **Returns:**
+
+ :ref:`DeviceCreateResponse`
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.create({
+ "name": "Temperature Sensor",
+ "network": "network-id-123",
+ "connector": "connector-id-456",
+ "type": "immutable",
+ "chunk_period": "month",
+ "chunk_retention": 6,
+ "active": True
+ })
+ print(result) # {'device_id': '...', 'bucket_id': '...', 'token': '...'}
+
+
+==========
+dataBackup
+==========
+
+Schedule to export the device's data to TagoIO Files.
+For mutable devices, exports all data. For immutable devices with chunkID, exports specific chunk.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/55-data-export Data Export
+ https://help.tago.io/portal/en/kb/articles/device-data#Backing_Up_Data Backing Up Data
+
+ **Parameters:**
+
+ | **params**: :ref:`DeviceDataBackup`
+ | Parameters for device data backup operation
+
+ | **chunkID**: Optional[:ref:`GenericID`]
+ | [Optional] Chunk ID if backup is for a specific chunk
+
+ **Returns:**
+
+ :ref:`DeviceDataBackupResponse`
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ import time
+ timestamp = int(time.time())
+ result = resources.devices.dataBackup({
+ "deviceID": "device-id-123",
+ "file_address": f"/backups/device-id-123/{timestamp}",
+ "headers": True
+ })
+ print(result) # {'file_address': 'backups/device-id-123/1736433519380.csv'}
+
+
+===========
+dataRestore
+===========
+
+Restores data to a device from a CSV file in TagoIO Files.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/device-data#Importing Importing Device Data
+ https://api.docs.tago.io/#7ebca255-6c38-43d3-97d0-9b62155f202e Import Data API
+
+ **Parameters:**
+
+ | **params**: :ref:`DeviceDataRestore`
+ | Parameters for device data restore operation
+
+ **Returns:**
+
+ str
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.dataRestore({
+ "deviceID": "device-id-123",
+ "file_address": "/backups/backup.csv"
+ })
+ print(result) # Data import added to the queue successfully!
+
+
======
delete
======
-Deletes an device from the account
+Permanently deletes a device from the account along with all its data.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
+ **Returns:**
-======
+ str
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.delete("device-id-123")
+ print(result) # Successfully Removed
+
+
+===========
+deleteChunk
+===========
+
+Deletes a chunk from an immutable device.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/chunk-management#Delete_chunks Delete Chunks
+
+ **Parameters:**
+
+ | **deviceID**: :ref:`GenericID`
+ | Device ID
+
+ | **chunkID**: :ref:`GenericID`
+ | Chunk ID
+
+ **Returns:**
+
+ str
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.deleteChunk("device-id-123", "chunk-id-123")
+ print(result) # Chunk chunk-id-123 deleted
+
+
+================
+deleteDeviceData
+================
+
+Deletes data from a device based on specified query parameters.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ **Parameters:**
+
+ | **deviceID**: :ref:`GenericID`
+ | Device ID
+
+ | **queryParam**: Optional[:ref:`DataQuery`]
+ | [Optional] Query parameters to filter the results
+
+ **Returns:**
+
+ str
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ # Delete specific records by ID
+ result = resources.devices.deleteDeviceData("device-id-123", {
+ "ids": ["record-id-1", "record-id-2"]
+ })
+ # Delete by variable
+ result = resources.devices.deleteDeviceData("device-id-123", {
+ "variables": ["old_sensor"],
+ "qty": 100
+ })
+ print(result) # Successfully Removed
+
+
+====
edit
-======
+====
-Modify any property of the device
+Modifies any property of an existing device.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
| **deviceObj**: :ref:`DeviceEditInfo`
| Device object with fields to replace
+ **Returns:**
-================
+ str
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.edit("device-id-123", {
+ "name": "Updated Sensor Name",
+ "active": False,
+ "tags": [{"key": "location", "value": "warehouse"}]
+ })
+ print(result) # Successfully Updated
+
+
+==============
+editDeviceData
+==============
+
+Modifies existing data records in a device. Requires the data record ID.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ **Parameters:**
+
+ | **deviceID**: :ref:`GenericID`
+ | Device ID
+
+ | **updatedData**: Union[DataEdit, List[DataEdit]]
+ | An array or one object with data to be updated
+
+ **Returns:**
+
+ str
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.editDeviceData("device-id-123", {
+ "id": "data-record-id",
+ "value": 30.0,
+ "unit": "°F"
+ })
+ # Edit multiple records
+ result = resources.devices.editDeviceData("device-id-123", [
+ {"id": "record-1-id", "value": 25.5},
+ {"id": "record-2-id", "value": 65}
+ ])
+ print(result) # Device Data Updated
+
+
+===============
emptyDeviceData
-================
+===============
+
+Permanently removes all data from a device. This operation cannot be undone.
+
+ **See:**
-Empty all data in a device.
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
+ **Returns:**
-================
-getDeviceData
-================
+ str
-Get data from all variables in the device.
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.emptyDeviceData("device-id-123")
+ print(result) # All data has been removed
+
+
+========
+getChunk
+========
+
+Retrieves chunk information from an immutable device.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/chunk-management Chunk Management
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
- | *Optional* **queryParams**: :ref:`DataQuery`
- | Query parameters to filter the results.
+ **Returns:**
+
+ List[:ref:`DeviceChunkData`]
.. code-block::
:caption: **Example:**
- from tagoio_sdk import Resources
+ resources = Resources()
+ chunks = resources.devices.getChunk("device-id-123")
+ print(chunks) # [{'amount': 0, 'id': 'chunk-id-123', 'from_date': '2025-01-09T00:00:00.000+00:00', ...}]
+
+
+=============
+getDeviceData
+=============
+
+Retrieves data from all variables in the device with optional query filters.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ **Parameters:**
+
+ | **deviceID**: :ref:`GenericID`
+ | Device ID
+
+ | **queryParams**: Optional[:ref:`DataQuery`]
+ | [Optional] Query parameters to filter the results
+
+ **Returns:**
+
+ List[:ref:`CommonData`]
+
+.. code-block::
+ :caption: **Example:**
resources = Resources()
- resources.devices.getDeviceData("myDeviceId");
+ # Get all data
+ data = resources.devices.getDeviceData("device-id-123")
+ # Get specific variable data
+ temp_data = resources.devices.getDeviceData("device-id-123", {
+ "variables": ["temperature"],
+ "qty": 10
+ })
+ print(temp_data) # [{'variable': 'temperature', 'value': 25.5, 'time': '...', ...}]
+
-=====
+====
info
-=====
+====
+
+Retrieves detailed information about a specific device.
+
+ **See:**
-Get Info of the Device
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
+ **Returns:**
+
+ :ref:`DeviceInfo`
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ device_info = resources.devices.info("device-id-123")
+ print(device_info) # {'id': '...', 'name': '...', 'type': 'mutable', ...}
+
==========
listDevice
==========
-Retrieves a list with all devices from the account
+Retrieves a list of all devices from the account with optional filtering and pagination.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
**Parameters:**
- | *Optional* **queryObj**: :ref:`DeviceQuery`
- | Search query params
+ | **queryObj**: Optional[:ref:`DeviceQuery`]
+ | [Optional] Search query params
+
+ **Returns:**
+
+ List[:ref:`DeviceListItem`]
.. code-block::
- :caption: **Default queryObj:**
+ :caption: **Example:**
- queryObj: {
+ resources = Resources()
+ devices = resources.devices.listDevice({
"page": 1,
- "fields": ["id", "name"],
- "filter": {},
"amount": 20,
- "orderBy": ["name", "asc"],
- "resolveBucketName": False
- }
+ "fields": ["id", "name", "active"],
+ "filter": {"name": "Temperature*"},
+ "orderBy": ["name", "asc"]
+ })
+ print(devices) # [{'id': 'device-id-123', 'name': 'Temperature Sensor', ...}]
+
=========
-paramSet
+paramList
=========
-Create or edit param for the Device
+Retrieves a list of configuration parameters for a device.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/configuration-parameters Configuration Parameters
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
- | **configObj**: :ref:`ConfigurationParams` or list[:ref:`ConfigurationParams`]
- | Configuration Data
+ | **sentStatus**: Optional[bool]
+ | [Optional] True return only sent=true, False return only sent=false
- | **paramID**: Optional[GenericID: str]
- | Parameter ID
+ **Returns:**
+ List[:ref:`ConfigurationParams`]
-==========
-paramList
-==========
+.. code-block::
+ :caption: **Example:**
-List Params for the Device
+ resources = Resources()
+ # Get all parameters
+ params = resources.devices.paramList("device-id-123")
+ # Get only sent parameters
+ sent_params = resources.devices.paramList("device-id-123", sentStatus=True)
+ print(params) # [{'id': '...', 'key': 'threshold', 'value': '25.5', 'sent': False}]
- **Parameters:**
- | **deviceID**: GenericID: str
- | Device ID
+===========
+paramRemove
+===========
- | *Optional* **sentStatus**: bool
- | True return only sent=true, False return only sent=false
+Removes a specific configuration parameter from a device.
-============
-paramRemove
-============
+ **See:**
-Remove param for the Device
+ https://help.tago.io/portal/en/kb/articles/configuration-parameters Configuration Parameters
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
- | **paramID**: GenericID: str
+ | **paramID**: :ref:`GenericID`
| Parameter ID
+ **Returns:**
-============
-tokenCreate
-============
+ str
+
+.. code-block::
+ :caption: **Example:**
-Generates and retrieves a new token
+ resources = Resources()
+ result = resources.devices.paramRemove("device-id-123", "param-id-456")
+ print(result) # Successfully Removed
- **Parameters:**
- | **deviceID**: GenericID: str
- | Device ID
+========
+paramSet
+========
- | **tokenParams**: :ref:`DevicesTokenData`
- | Params for new token
+Creates new configuration parameters or updates existing ones for a device.
-============
-tokenDelete
-============
+ **See:**
-Delete a token
+ https://help.tago.io/portal/en/kb/articles/configuration-parameters Configuration Parameters
**Parameters:**
- | **token**: GenericToken: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
-==========
-tokenList
-==========
+ | **configObj**: Union[:ref:`ConfigurationParams`, List[:ref:`ConfigurationParams`]]
+ | Configuration Data
-Retrieves a list of all tokens
+ | **paramID**: Optional[:ref:`GenericID`]
+ | [Optional] Parameter ID
- **Parameters:**
+ **Returns:**
- | **token**: GenericToken: str
- | Device ID
-
- | *Optional* **queryObj**: :ref:`ListDeviceTokenQuery`
- | Search query params
+ str
.. code-block::
- :caption: **Default queryObj:**
+ :caption: **Example:**
+
+ resources = Resources()
+ # Create new parameter
+ result = resources.devices.paramSet("device-id-123", {
+ "key": "threshold",
+ "value": "25.5",
+ "sent": False
+ })
+ # Update existing parameter
+ result = resources.devices.paramSet("device-id-123", {
+ "key": "threshold",
+ "value": "30.0",
+ "sent": False
+ }, "param-id-456")
+ print(result) # Successfully Updated
- queryObj: {
- "page": 1,
- "fields": ["name", "token", "permission"],
- "filter": {},
- "amount": 20,
- "orderBy": ["created_at", "desc"],
- }
==============
sendDeviceData
==============
-Send data to a device.
+Sends data to a device. Accepts a single data object or an array of data objects.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
- | **data**: Union[:ref:`CommonData`, list[:ref:`CommonData`]]
- | An array or one object with data to be send to TagoIO.
+ | **data**: Union[DataCreate, List[DataCreate]]
+ | An array or one object with data to be sent to TagoIO
+
+ **Returns:**
+
+ str
.. code-block::
:caption: **Example:**
- from tagoio_sdk import Resources
-
resources = Resources()
- resource.devices.sendDeviceData("myDeviceID", {
+ result = resources.devices.sendDeviceData("device-id-123", {
"variable": "temperature",
- "unit": "F",
- "value": 55,
- "time": "2015-11-03 13:44:33",
- "location": { "lat": 42.2974279, "lng": -85.628292 },
+ "value": 25.5,
+ "unit": "°C",
+ "time": "2025-01-09 13:44:33",
+ "location": {"lat": 42.2974279, "lng": -85.628292}
})
+ # Send multiple data points
+ result = resources.devices.sendDeviceData("device-id-123", [
+ {"variable": "temperature", "value": 25.5},
+ {"variable": "humidity", "value": 60}
+ ])
+ print(result) # Successfully Inserted
-==============
-editDeviceData
-==============
-Edit data in a device.
+===========
+tokenCreate
+===========
+
+Generates and retrieves a new authentication token for a device.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/495-access-tokens Device Tokens
**Parameters:**
- | **deviceID**: GenericID: str
+ | **deviceID**: :ref:`GenericID`
| Device ID
- | **updatedData**: Union[:ref:`CommonData`, list[:ref:`CommonData`]]
- | An array or one object with data to be send to TagoIO.
+ | **tokenParams**: :ref:`CommonTokenData`
+ | Params for new token
+
+ **Returns:**
+
+ :ref:`TokenCreateResponse`
.. code-block::
:caption: **Example:**
- resources = Resource()
- resource.devices.editDeviceData("myDeviceID", {
- "id": "idOfTheRecord",
- "value": "new value",
- "unit": "new unit"
- })
+ resources = Resources()
+ result = resources.devices.tokenCreate("device-id-123", {
+ "name": "Production Token",
+ "permission": "write",
+ "expire_time": "never"
+ })
+ print(result) # {'token': 'new-token-value', 'expire_date': None}
-================
-deleteDeviceData
-================
-Delete data from a device.
+===========
+tokenDelete
+===========
+
+Permanently deletes an authentication token.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/495-access-tokens Device Tokens
**Parameters:**
- | **deviceID**: GenericID: str
+ | **token**: :ref:`GenericToken`
+ | Token to delete
+
+ **Returns:**
+
+ str
+
+.. code-block::
+ :caption: **Example:**
+
+ resources = Resources()
+ result = resources.devices.tokenDelete("token-to-delete")
+ print(result) # Successfully Removed
+
+
+=========
+tokenList
+=========
+
+Retrieves a list of all authentication tokens for a device with optional filtering.
+
+ **See:**
+
+ https://help.tago.io/portal/en/kb/articles/495-access-tokens Device Tokens
+
+ **Parameters:**
+
+ | **deviceID**: :ref:`GenericID`
| Device ID
- | *Optional* **queryParams**: :ref:`DataQuery`
- | Query parameters to filter the results.
+ | **queryObj**: Optional[:ref:`ListDeviceTokenQuery`]
+ | [Optional] Search query params
+
+ **Returns:**
+
+ List[:ref:`DeviceTokenDataList`]
.. code-block::
:caption: **Example:**
- resources = Resource()
- resource.devices.deleteDeviceData("myDeviceID", {
- "ids": ["recordIdToDelete", "anotherRecordIdToDelete" ]
- })
+ resources = Resources()
+ tokens = resources.devices.tokenList("device-id-123", {
+ "page": 1,
+ "amount": 20,
+ "fields": ["name", "token", "permission"],
+ "orderBy": ["created_at", "desc"]
+ })
+ print(tokens) # [{'name': 'Default Token', 'token': '...', 'permission': 'full', ...}]
+
.. toctree::
diff --git a/docs/source/Resources/IntegrationNetwork/IntegrationNetwork_Type.rst b/docs/source/Resources/IntegrationNetwork/IntegrationNetwork_Type.rst
index 986d6a4..ff2ab4f 100644
--- a/docs/source/Resources/IntegrationNetwork/IntegrationNetwork_Type.rst
+++ b/docs/source/Resources/IntegrationNetwork/IntegrationNetwork_Type.rst
@@ -96,3 +96,43 @@ TokenData
| **serie_number**: Optional[str]
| **verification_code**: Optional[str]
| **middleware**: Optional[str]
+
+
+.. _NetworkTokenInfo:
+
+NetworkTokenInfo
+----------------
+ **Attributes:**
+
+ | **token**: str
+ | **network**: :ref:`GenericID`
+ | **name**: str
+ | **permission**: str
+ | **created_at**: datetime
+ | **updated_at**: Optional[datetime]
+
+
+.. _NetworkQuery:
+
+NetworkQuery
+------------
+ **Attributes:**
+
+ | **page**: int
+ | **amount**: int
+ | **fields**: list[str]
+ | **filter**: dict
+ | **orderBy**: list[str]
+
+
+.. _ListTokenQuery:
+
+ListTokenQuery
+--------------
+ **Attributes:**
+
+ | **page**: int
+ | **amount**: int
+ | **fields**: list[str]
+ | **filter**: dict
+ | **orderBy**: list[str]
diff --git a/docs/source/Resources/IntegrationNetwork/index.rst b/docs/source/Resources/IntegrationNetwork/index.rst
index 703d5b5..8f79334 100644
--- a/docs/source/Resources/IntegrationNetwork/index.rst
+++ b/docs/source/Resources/IntegrationNetwork/index.rst
@@ -1,29 +1,277 @@
**Integration Network**
=======================
-Manage integration network in the account
+Manage integration networks in the account.
============
listNetwork
============
-Get list of networks
+
+Retrieves a list of all networks from the account with pagination support.
+Use this to retrieve and manage networks in your application.
+
+See: `Network Integration `_
**Parameters:**
- | **queryObj**: :ref:`Query`
- | Network Query
+ | *Optional* **queryObj**: :ref:`NetworkQuery`
+ | Query parameters to filter the results.
+
+ .. code-block::
+ :caption: **Default queryObj:**
+
+ queryObj = {
+ "page": 1,
+ "fields": ["id", "name"],
+ "filter": {},
+ "amount": 20,
+ "orderBy": ["name", "asc"]
+ }
+
+ **Returns:**
+
+ | List[:ref:`NetworkInfo`]
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Access" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ networks = resources.integration.networks.listNetwork({
+ "page": 1,
+ "fields": ["id", "name"],
+ "amount": 20,
+ "orderBy": ["name", "asc"]
+ })
+ print(networks) # [{'id': 'network-id-123', 'name': 'My Network', ...}]
======
info
======
-Gets information about the network
+Retrieves detailed information about a specific network.
+
+See: `Network Integration `_
+
+ **Parameters:**
+
+ | **networkID**: :ref:`GenericID`
+ | Network ID
+
+ | *Optional* **fields**: List[str]
+ | Fields to retrieve (default: ["id", "name"])
+
+ **Returns:**
+
+ | :ref:`NetworkInfo`
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Access" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ network_info = resources.integration.networks.info("network-id-123")
+ print(network_info) # {'id': '...', 'name': 'My Network', ...}
+
+
+======
+create
+======
+
+Creates a new integration network in the account.
+
+See: `Creating a Network Integration `_
+
+ **Parameters:**
+
+ | **networkObj**: :ref:`NetworkCreateInfo`
+ | Network information
+
+ **Returns:**
+
+ | Dict[str, str]
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Create" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ new_network = resources.integration.networks.create({
+ "name": "My Custom Network",
+ "description": "Custom integration network",
+ "middleware_endpoint": "https://my-middleware.com/endpoint",
+ "public": False
+ })
+ print(new_network) # {'network': 'network-id-123'}
+
+
+======
+edit
+======
+
+Modifies any property of an existing network.
+
+ **Parameters:**
+
+ | **networkID**: :ref:`GenericID`
+ | Network ID
+
+ | **networkObj**: :ref:`NetworkCreateInfo`
+ | Network information to update
+
+ **Returns:**
+
+ | str
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Edit" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.integration.networks.edit("network-id-123", {
+ "name": "Updated Network Name",
+ "description": "Updated description",
+ "public": True
+ })
+ print(result) # Successfully Updated
+
+
+======
+delete
+======
+
+Permanently deletes a network from the account.
**Parameters:**
- | **networkID**: GenericID: str
- | Network identification
+ | **networkID**: :ref:`GenericID`
+ | Network ID
+
+ **Returns:**
+
+ | str
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Delete" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.integration.networks.delete("network-id-123")
+ print(result) # Successfully Removed
+
+
+==========
+tokenList
+==========
+
+Retrieves a list of all authentication tokens for a network with optional filtering.
+
+See: `Tokens and Getting Devices `_
+
+ **Parameters:**
+
+ | **networkID**: :ref:`GenericID`
+ | Network ID
+
+ | *Optional* **queryObj**: :ref:`ListTokenQuery`
+ | Query parameters to filter the results.
+
+ .. code-block::
+ :caption: **Default queryObj:**
+
+ queryObj = {
+ "page": 1,
+ "fields": ["name", "token", "permission"],
+ "filter": {},
+ "amount": 20,
+ "orderBy": ["created_at", "desc"]
+ }
+
+ **Returns:**
+
+ | List[:ref:`NetworkTokenInfo`]
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Access" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ tokens = resources.integration.networks.tokenList("network-id-123", {
+ "page": 1,
+ "amount": 20,
+ "fields": ["name", "token", "permission"],
+ "orderBy": ["created_at", "desc"]
+ })
+ print(tokens) # [{'name': 'Default Token', 'token': '...', 'permission': 'full', ...}]
+
+
+===========
+tokenCreate
+===========
+
+Generates and retrieves a new authentication token for a network.
+
+See: `Tokens and Getting Devices `_
+
+ **Parameters:**
+
+ | **networkID**: :ref:`GenericID`
+ | Network ID
+
+ | **tokenParams**: :ref:`IntegrationTokenData`
+ | Parameters for the new token
+
+ **Returns:**
+
+ | :ref:`TokenCreateResponse`
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Create Token" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.integration.networks.tokenCreate("network-id-123", {
+ "name": "Production Token",
+ "permission": "write",
+ "expire_time": "never"
+ })
+ print(result) # {'token': 'new-token-value', 'expire_date': None}
+
+
+===========
+tokenDelete
+===========
+
+Permanently deletes an authentication token.
+
+See: `Tokens and Getting Devices `_
+
+ **Parameters:**
+
+ | **token**: :ref:`GenericToken`
+ | Token to delete
+
+ **Returns:**
+
+ | str
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy "Integration Network" / "Delete Token" in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.integration.networks.tokenDelete("token-to-delete")
+ print(result) # Successfully Removed
+
.. toctree::
diff --git a/docs/source/Resources/Profile/Profile_Types.rst b/docs/source/Resources/Profile/Profile_Types.rst
index 98e34cd..39453c8 100644
--- a/docs/source/Resources/Profile/Profile_Types.rst
+++ b/docs/source/Resources/Profile/Profile_Types.rst
@@ -226,3 +226,230 @@ TypedDict representing the summary of a profile.
| **addons**: :ref:`ProfileAddOns`
| The add-ons of the profile.
+
+
+.. _UsageStatistic:
+
+UsageStatistic
+-----------------
+TypedDict representing a single usage statistic with timestamp.
+
+Not all of the services will be present for every statistic, only if for the usage period the service was used.
+
+ **Properties:**
+
+ | **time**: datetime
+ | Timestamp for the usage statistic.
+
+ | **input**: Union[int, float]
+ | Input data usage.
+
+ | **output**: Union[int, float]
+ | Output data usage.
+
+ | **analysis**: Union[int, float]
+ | Analysis execution time used.
+
+ | **sms**: Union[int, float]
+ | SMS messages sent.
+
+ | **email**: Union[int, float]
+ | Email messages sent.
+
+ | **data_records**: Union[int, float]
+ | Data records stored.
+
+ | **run_users**: Union[int, float]
+ | Run users used.
+
+ | **push_notification**: Union[int, float]
+ | Push notifications sent.
+
+ | **file_storage**: Union[int, float]
+ | File storage used.
+
+ | **tcore**: Union[int, float]
+ | TCore resources used.
+
+
+.. _AuditLogEvent:
+
+AuditLogEvent
+-----------------
+TypedDict representing a single audit log event.
+
+ **Properties:**
+
+ | **resourceName**: str
+ | Name of the resource that triggered the event.
+
+ | **message**: str
+ | Descriptive message about the event.
+
+ | **resourceID**: :ref:`GenericID`
+ | ID of the resource that triggered the event.
+
+ | **who**: :ref:`GenericID`
+ | ID of the account that performed the action.
+
+ | **date**: datetime
+ | Timestamp when the event occurred.
+
+
+.. _AuditLogStatistics:
+
+AuditLogStatistics
+------------------
+TypedDict representing statistics for an audit log query.
+
+ **Properties:**
+
+ | **recordsMatched**: int
+ | Number of records that matched the query.
+
+ | **recordsScanned**: int
+ | Number of records scanned during the query.
+
+ | **bytesScanned**: int
+ | Number of bytes scanned during the query.
+
+
+.. _AuditLog:
+
+AuditLog
+-----------------
+TypedDict representing an audit log query result.
+
+ **Properties:**
+
+ | **events**: list[:ref:`AuditLogEvent`]
+ | List of audit log events.
+
+ | **statistics**: :ref:`AuditLogStatistics`
+ | Statistics about the query execution.
+
+ | **status**: Literal["Running", "Complete", "Failed", "Timeout", "Unknown"]
+ | Current status of the audit log query.
+
+ | **queryId**: str
+ | Unique identifier for the audit log query.
+
+
+.. _AuditLogFilter:
+
+AuditLogFilter
+-----------------
+TypedDict representing filters for audit log queries.
+
+ **Properties:**
+
+ | **resourceID**: :ref:`GenericID`
+ | Filter by specific resource ID.
+
+ | **resourceName**: Literal["action", "am", "analysis", "connector", "dashboard", "device", "dictionary", "network", "profile", "run", "runuser"]
+ | Filter by resource type.
+
+ | **find**: str
+ | Search string for filtering events.
+
+ | **start_date**: Union[str, datetime]
+ | Start date for the query range.
+
+ | **end_date**: Union[str, datetime]
+ | End date for the query range.
+
+ | **limit**: int
+ | Maximum number of results to return.
+
+
+.. _AddonInfo:
+
+AddonInfo
+-----------------
+TypedDict representing profile addon information.
+
+ **Properties:**
+
+ | **id**: :ref:`GenericID`
+ | The addon ID.
+
+ | **name**: str
+ | The addon name.
+
+ | **logo_url**: Optional[str]
+ | URL of the addon's logo.
+
+
+.. _StatisticsDate:
+
+StatisticsDate
+-----------------
+TypedDict representing parameters for fetching usage statistics.
+
+ **Properties:**
+
+ | **timezone**: str
+ | Timezone to be used in the statistics entries (default: "UTC").
+
+ | **date**: Union[str, datetime]
+ | Timestamp for fetching hourly statistics in a day.
+
+ | **start_date**: Union[str, datetime]
+ | Starting date for fetching statistics in an interval.
+
+ | **end_date**: Union[str, datetime]
+ | End date for fetching statistics in an interval.
+
+ | **periodicity**: Literal["hour", "day", "month"]
+ | Periodicity of the statistics to fetch (default: "hour").
+
+
+.. _ProfileTeam:
+
+ProfileTeam
+-----------------
+TypedDict representing a team member with access to a profile.
+
+ **Properties:**
+
+ | **active**: bool
+ | Whether the team member's access is active.
+
+ | **created_at**: datetime
+ | When the team member was added.
+
+ | **email**: str
+ | Email address of the team member.
+
+ | **id**: str
+ | Account ID of the team member.
+
+ | **name**: str
+ | Name of the team member.
+
+
+.. _ProfileCreateInfo:
+
+ProfileCreateInfo
+-----------------
+TypedDict representing the information needed to create a new profile.
+
+ **Properties:**
+
+ | **name**: str
+ | Name of the profile to be created.
+
+
+.. _ProfileCredentials:
+
+ProfileCredentials
+------------------
+TypedDict representing credentials required for sensitive profile operations.
+
+ **Properties:**
+
+ | **password**: str
+ | Account password.
+
+ | **pin_code**: str
+ | Two-factor authentication PIN code (required when 2FA is enabled).
diff --git a/docs/source/Resources/Profile/index.rst b/docs/source/Resources/Profile/index.rst
index 8f884fe..4f66a67 100644
--- a/docs/source/Resources/Profile/index.rst
+++ b/docs/source/Resources/Profile/index.rst
@@ -1,98 +1,518 @@
**Profile**
-============
+===========
-Manage profiles in account.
+Manage profiles in your TagoIO account.
====
info
====
-Gets information about the bucket
+Retrieves detailed information about a specific profile using its ID or 'current' for the active profile.
+
+See: `Profiles `_
**Parameters:**
- | **profileID**: GenericID: str
- | Profile identification
+ | **profileID**: :ref:`GenericID`
+ | Profile identification (use "current" for the active profile)
**Returns:**
- | **result**: :ref:`ProfileInfo`
+ | :ref:`ProfileInfo`
-.. code-block::
- :caption: **Example:**
+ .. code-block:: python
+ # If receive an error "Authorization Denied", check policy **Account** / **Access profile** in Access Management.
from tagoio_sdk import Resources
resources = Resources()
- result = resources.profile.info("Profile ID")
+ profile_info = resources.profile.info("profile-id-123")
+ # Or get current profile
+ current_profile = resources.profile.info("current")
+ print(profile_info) # {'info': {'id': 'profile-id-123', 'account': 'account-id-123', ...}, ...}
+
====
list
====
-Lists all the profiles in your account
+Retrieves a list of all profiles associated with the current account.
+
+See: `Profiles `_
**Returns:**
- | **result**: list[:ref:`ProfileListInfo`]
+ | list[:ref:`ProfileListInfo`]
-.. code-block::
- :caption: **Example:**
+ .. code-block:: python
+ # If receive an error "Authorization Denied", check policy **Account** / **Access profile** in Access Management.
from tagoio_sdk import Resources
resources = Resources()
result = resources.profile.list()
+ print(result) # [{'id': 'profile-id-123', 'name': 'Profile Test', ...}]
-========
+=======
summary
-========
+=======
+
+Retrieves a summary of the profile's usage and statistics.
-Gets profile summary
+See: `Profiles `_
**Parameters:**
- | **profileID**: GenericID: str
+ | **profileID**: :ref:`GenericID`
| Profile identification
**Returns:**
- | **result**: :ref:`ProfileSummary`
+ | :ref:`ProfileSummary`
-.. code-block::
- :caption: **Example:**
+ .. code-block:: python
+ # If receive an error "Authorization Denied", check policy **Account** / **Access profile** in Access Management.
from tagoio_sdk import Resources
resources = Resources()
- result = resources.profile.summary("Profile ID")
+ result = resources.profile.summary("profile-id-123")
+ print(result) # {'amount': {'device': 10, 'bucket': 10, 'dashboard': 5, ...}, ...}
=========
tokenList
=========
-Gets profile tokenList
+Retrieves a list of all tokens associated with a specific profile.
+
+See: `Account Token `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | *Optional* **queryObj**: :ref:`Query`
+ | Query parameters to filter the results
+
+ .. code-block::
+ :caption: **Default queryObj:**
+
+ queryObj = {
+ "page": 1,
+ "amount": 20,
+ "fields": ["name", "token", "permission"],
+ "filter": {},
+ "orderBy": ["created_at", "asc"]
+ }
+
+ **Returns:**
+
+ | list[:ref:`TokenDataList`]
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.tokenList("profile-id-123", {
+ "page": 1,
+ "amount": 20,
+ "fields": ["name", "token", "permission"]
+ })
+ print(result) # [{'name': 'Token #1', 'token': 'token-value', 'permission': 'full', ...}, ...]
+
+
+======
+create
+======
+
+Creates a new profile with the specified name and optional resource allocation settings.
+
+See: `Profiles `_
+
+ **Parameters:**
+
+ | **profileObj**: :ref:`ProfileCreateInfo`
+ | Profile information to create
+
+ | *Optional* **allocate_free_resources**: bool
+ | Whether to allocate free resources to the new profile (default: False)
+
+ **Returns:**
+
+ | dict with key "id" containing the new profile ID
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.create({"name": "New Profile"}, allocate_free_resources=True)
+ print(result) # {'id': 'profile-id-123'}
+
+
+====
+edit
+====
+
+Updates profile information with the provided data.
+
+See: `Profiles `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | **profileObj**: dict
+ | Profile information to update
+
+ **Returns:**
+
+ | str - Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.edit("profile-id-123", {"name": "Updated Profile Name"})
+ print(result) # Successfully Updated
+
+
+======
+delete
+======
+
+Permanently removes a profile from the account.
+
+See: `Two-Factor Authentication (2FA) `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | **credentials**: :ref:`ProfileCredentials`
+ | Account credentials (password and pin_code if 2FA is enabled)
+
+ **Returns:**
+
+ | str - Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ # The "pin_code" field is required when 2FA is activated
+ result = resources.profile.delete("profile-id-123", {"password": "your-password", "pin_code": "123456"})
+ print(result) # Successfully Removed
+
+
+==================
+usageStatisticList
+==================
+
+Retrieves usage statistics for a profile within a specified time period.
+
+Usage statistics are cumulative: if a service was not used in a time period, the statistics for that time period will not be in the object.
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | *Optional* **dateObj**: :ref:`StatisticsDate`
+ | Date range and periodicity parameters
+
+ **Returns:**
+
+ | list[:ref:`UsageStatistic`]
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy **Account** / **Access profile statistics** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.profile.usageStatisticList("profile-id-123", {
+ "start_date": "2024-09-01",
+ "end_date": "2024-12-31",
+ "periodicity": "day"
+ })
+ print(result) # [{'time': '2024-09-02T00:01:29.749Z', 'analysis': 0.07, 'data_records': 67254, ...}, ...]
+
+
+========
+auditLog
+========
+
+Creates a new audit log query for tracking profile activities.
+
+See: `Audit Log `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | *Optional* **filterObj**: :ref:`AuditLogFilter`
+ | Filters to apply to the audit log query
+
+ **Returns:**
+
+ | :ref:`AuditLog`
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.auditLog("profile-id-123", {
+ "start_date": "2024-12-01",
+ "end_date": "2024-12-07"
+ })
+ print(result)
+
+
+==============
+auditLogQuery
+==============
+
+Retrieves audit log entries using a previously created query.
+
+See: `Audit Log `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | **queryId**: str
+ | Query ID from a previous auditLog call
+
+ **Returns:**
+
+ | :ref:`AuditLog`
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.auditLogQuery("profile-id-123", "query-id-456")
+ print(result)
+
+
+===========
+serviceEdit
+===========
+
+Updates service configuration and resource limits for a profile.
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | **serviceObj**: dict
+ | Service configuration and resource limits to update
+
+ **Returns:**
+
+ | str - Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.serviceEdit("profile-id-123", {
+ "input": 350000,
+ "output": 342153,
+ "analysis": 5
+ })
+ print(result) # Profile resource allocation Successfully Updated
+
+
+=================================
+transferTokenToAnotherProfile
+=================================
+
+Transfers the current authentication token to another profile.
+
+ **Parameters:**
+
+ | **targetProfileID**: :ref:`GenericID`
+ | Target profile identification
+
+ **Returns:**
+
+ | str - Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.transferTokenToAnotherProfile("target-profile-123")
+ print(result)
+
+
+===========
+tokenCreate
+===========
+
+Creates a new authentication token for the specified profile.
+
+See: `Account Token `_
+
+See: `Two-Factor Authentication (2FA) `_
**Parameters:**
- | **profileID**: GenericID: str
+ | **profileID**: :ref:`GenericID`
| Profile identification
- | **queryObj**: Optional[:ref:`Query`]
- | Token Query
+
+ | **tokenParams**: :ref:`CommonTokenData`
+ | Token parameters including name, permission, email, and password
**Returns:**
- | **result**: list[:ref:`TokenDataList`]
+ | :ref:`TokenCreateResponse`
-.. code-block::
- :caption: **Example:**
+ .. code-block:: python
from tagoio_sdk import Resources
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ # The "pin_code" / "otp_type" field is required when 2FA is activated
+ result = resources.profile.tokenCreate("profile-id-123", {
+ "name": "API Access",
+ "permission": "full",
+ "email": "example@email.com",
+ "password": "your-password"
+ })
+ print(result) # {'token': 'token-value', 'name': 'API Access', ...}
+
+
+===========
+tokenDelete
+===========
+
+Revokes and removes an authentication token from the profile.
+
+See: `Account Token `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | **token**: :ref:`GenericToken`
+ | Token to be deleted
+
+ **Returns:**
+
+ | str - Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.tokenDelete("profile-id-123", "token-xyz")
+ print(result) # Token Successfully Removed
+
+
+=============
+addTeamMember
+=============
+
+Adds a new team member to the profile using their email address.
+
+See: `Team Management - Sharing your Profile `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | **email**: str
+ | Email address of the team member to invite
+
+ **Returns:**
+
+ | str - Success message
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.addTeamMember("profile-id-123", "user@example.com")
+ print(result) # User invited
+
+
+========
+teamList
+========
+
+Retrieves a list of all team members that have access to the specified profile.
+
+See: `Team Management - Sharing your Profile `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ **Returns:**
+
+ | list[:ref:`ProfileTeam`]
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.teamList("profile-id-123")
+ print(result) # [{'id': 'account-id-123', 'active': False, 'name': 'John Doe', ...}, ...]
+
+
+================
+deleteTeamMember
+================
+
+Removes a team member from the profile.
+
+See: `Team Management - Sharing your Profile `_
+
+ **Parameters:**
+
+ | **profileID**: :ref:`GenericID`
+ | Profile identification
+
+ | **accountId**: str
+ | Account ID of the team member to remove
+
+ **Returns:**
+
+ | str - Success message
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy in Access Management.
+ from tagoio_sdk import Resources
+
resources = Resources()
- result = resources.profile.tokenList("Profile ID")
+ result = resources.profile.deleteTeamMember("profile-id-123", "account-id-456")
+ print(result) # Account Successfully Removed
+
.. toctree::
diff --git a/docs/source/Resources/Run/Run_Types.rst b/docs/source/Resources/Run/Run_Types.rst
index 588da9b..0620063 100644
--- a/docs/source/Resources/Run/Run_Types.rst
+++ b/docs/source/Resources/Run/Run_Types.rst
@@ -319,6 +319,21 @@ LoginAsUserOptions
| :default: "8 hours"
+.. _EmailTestData:
+
+EmailTestData
+-------------
+
+Type for the email test data.
+
+ **Attributes:**
+
+ | **subject**: str
+ | Subject of the test email.
+
+ | **body**: str
+ | Body content of the test email.
+
.. _SAMLAttributeMappings:
diff --git a/docs/source/Resources/Run/index.rst b/docs/source/Resources/Run/index.rst
index 3a27538..ce60e23 100644
--- a/docs/source/Resources/Run/index.rst
+++ b/docs/source/Resources/Run/index.rst
@@ -1,320 +1,543 @@
-
**Run**
-========
+=======
-Manage services in account.
+Manage TagoRUN environment configuration and users.
-=======
+====
info
-=======
+====
-Get information about the TagoRUN service.
+Retrieves information about the current Run environment configuration.
- **Returns**
+See: `TagoRun `_ | `Run Themes `_
- | **result**: :ref:`RunInfo`
- | Information about the TagoRUN service.
+ **Returns:**
+ | :ref:`RunInfo`
-=======
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy **Profile** / **Access TagoRun settings** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.info()
+ print(result) # {'name': 'My Run Environment', 'logo': 'https://example.com/logo.png', ...}
+
+
+====
edit
-=======
+====
+
+Updates the Run environment configuration settings.
-Edit the TagoRUN service information.
+See: `TagoRun `_ | `Run Themes `_
**Parameters:**
- | **data**: :ref:`RunInfo`
- | Updated information for the TagoRUN service.
+ | **data**: dict
+ | Run configuration data to update
**Returns:**
- | **result**: str
- | Success message.
+ | str
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy **Profile** / **Edit TagoRun settings** in Access Management.
+ from tagoio_sdk import Resources
+ resources = Resources()
+ result = resources.run.edit({"name": "My Run Environment", "logo": "https://example.com/logo.png"})
+ print(result) # TagoIO Run Successfully Updated
-============
+
+=========
listUsers
-============
+=========
+
+Retrieves a paginated list of Run users with customizable fields and filtering options.
-List users in the TagoRUN service.
+See: `TagoRun `_
**Parameters:**
| **query**: :ref:`Query`
- | Query parameters for filtering and sorting the user list.
+ | Query parameters for filtering and sorting
- **Returns:**
+ .. code-block::
+ :caption: **Default query:**
- | **result**: list[:ref:`UserInfo`]
- | List of user information.
+ query = {
+ "page": 1,
+ "fields": ["id", "name"],
+ "filter": {},
+ "amount": 20,
+ "orderBy": ["name", "asc"]
+ }
+ **Returns:**
-============
-userInfo
-============
-
-Get information about a specific user in the TagoRUN service.
+ | list[:ref:`UserInfo`]
- **Parameters:**
+ .. code-block:: python
- | **userID**: :ref:`GenericID`
- | ID of the user.
+ # If receive an error "Authorization Denied", or return empty list check policy **Run User** / **Access** in Access Management.
+ from tagoio_sdk import Resources
- **Returns:**
+ resources = Resources()
+ result = resources.run.listUsers({
+ "page": 1,
+ "fields": ["id", "name", "email"],
+ "amount": 20
+ })
+ print(result) # [{'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com'}]
- | **result**: :ref:`UserInfo`
- | Information about the user.
+========
+userInfo
+========
-================
-userCreate
-================
+Retrieves detailed information about a specific Run user.
-Create a new user in the TagoRUN service.
+See: `TagoRun `_
**Parameters:**
- | **data**: :ref:`UserCreateInfo`
- | Information for creating the user.
+ | **userID**: :ref:`GenericID`
+ | User identification
**Returns:**
- | **result**: str
- | Success message.
+ | :ref:`UserInfo`
+ .. code-block:: python
-================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Access** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.userInfo("user-id-123")
+ print(result) # {'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com', ...}
+
+
+==========
userCreate
-================
+==========
+
+Creates a new user in the Run environment.
-Create a new user in the TagoRUN service.
+See: `TagoRun `_
**Parameters:**
| **data**: :ref:`UserCreateInfo`
- | Information for creating the user.
+ | User creation data
**Returns:**
- | **result**: str
- | Success message.
+ | dict
+ .. code-block:: python
-================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Create** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.userCreate({
+ "name": "John Doe",
+ "email": "john@example.com",
+ "password": "secure123",
+ "timezone": "America/New_York"
+ })
+ print(result) # {'user': 'user-id-123'}
+
+
+========
userEdit
-================
+========
-Edit information about a specific user in the TagoRUN service.
+Updates information for an existing Run user.
+
+See: `TagoRun `_
**Parameters:**
| **userID**: :ref:`GenericID`
- | ID of the user.
+ | User identification
- | **data**: :ref:`UserInfo`
- | Updated information for the user.
+ | **data**: dict
+ | User data to update
**Returns:**
- | **result**: str
- | Success message.
+ | str
+ .. code-block:: python
-==================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Edit** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.userEdit("user-id-123", {"name": "Updated Name"})
+ print(result) # TagoIO Run User Successfully Updated
+
+
+==========
userDelete
-==================
+==========
+
+Permanently deletes a user from the Run environment.
-Delete a specific user from the TagoRUN service.
+See: `TagoRun `_
**Parameters:**
| **userID**: :ref:`GenericID`
- | ID of the user.
+ | User identification
**Returns:**
- | **result**: str
- | Success message.
+ | str
+ .. code-block:: python
-==================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Delete** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.userDelete("user-id-123")
+ print(result) # Successfully Removed
+
+
+===========
loginAsUser
-==================
+===========
-Log in as a specific user in the TagoRUN service.
+Generates a login token to authenticate as a specific Run user.
**Parameters:**
| **userID**: :ref:`GenericID`
- | ID of the user.
+ | User identification
- | **options**: Optional[:ref:`LoginAsUserOptions`]
- | Additional options for the login.
+ | *Optional* **options**: :ref:`LoginAsUserOptions`
+ | Login options (e.g., expire_time)
**Returns:**
- | **result**: :ref:`LoginResponseRunUser`
- | Login response.
+ | :ref:`LoginResponse`
+ .. code-block:: python
-================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Login as user** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.loginAsUser("user-id-123")
+ print(result["token"]) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
+
+
+=========
emailTest
-================
+=========
-Send a test email from the TagoRUN service.
+Tests the email configuration by sending a test message.
**Parameters:**
- | **data**: :ref:`EmailBase`
- | Email data including subject and body.
+ | **data**: :ref:`EmailTestData`
+ | Email test data with subject and body
**Returns:**
- | **result**: str
- | Success message.
+ | str
+ .. code-block:: python
-======================
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.emailTest({"subject": "Test Email", "body": "This is a test message"})
+ print(result) # E-mail sent to example@email.com
+
+
+================
notificationList
-======================
+================
+
+Retrieves a list of notifications for a specific Run user.
-List notifications for a specific user in the TagoRUN service.
+See: `Notifications for Users `_
**Parameters:**
| **userID**: :ref:`GenericID`
- | ID of the user.
+ | User identification
**Returns:**
- | **result**: list[:ref:`NotificationInfo`]
- | List of notification information.
+ | list[:ref:`NotificationInfo`]
+ .. code-block:: python
-======================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Access notification** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.notificationList("user-id-123")
+ print(result) # [{'id': 'notification-id-123', 'title': 'System Update', 'message': 'Features', ...}]
+
+
+==================
notificationCreate
-======================
+==================
-Create a new notification for a specific user in the TagoRUN service.
+Creates a new notification for a Run user.
+
+See: `Notifications for Users `_
**Parameters:**
| **userID**: :ref:`GenericID`
- | ID of the user.
+ | User identification
| **data**: :ref:`NotificationCreate`
- | Information for creating the notification.
+ | Notification data
**Returns:**
- | **result**: :ref:`NotificationCreateReturn`
- | Information about the created notification.
+ | :ref:`NotificationCreateReturn`
+ .. code-block:: python
-======================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Create notification** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.notificationCreate("user-id-123", {
+ "title": "Update",
+ "message": "New feature available"
+ })
+ print(result) # {'id': 'notification-id-123'}
+
+
+================
notificationEdit
-======================
+================
+
+Updates an existing notification in the Run environment.
-Edit information about a specific notification in the TagoRUN service.
+See: `Notifications for Users `_
**Parameters:**
| **notificationID**: :ref:`GenericID`
- | ID of the notification.
+ | Notification identification
- | **data**: :ref:`NotificationCreate`
- | Updated information for the notification.
+ | **data**: dict
+ | Notification data to update
**Returns:**
- | **result**: str
- | Success message.
+ | str
+ .. code-block:: python
-======================
+ # If receive an error "Authorization Denied", check policy **Run User** / **Edit notification** in Access Management.
+ from tagoio_sdk import Resources
+
+ resources = Resources()
+ result = resources.run.notificationEdit("notification-id-123", {"title": "Updated Title"})
+ print(result) # TagoIO Notification User Successfully Updated
+
+
+==================
notificationDelete
-======================
+==================
-Delete a specific notification from the TagoRUN service.
+Deletes a notification from the Run environment.
+
+See: `Notifications for Users `_
**Parameters:**
| **notificationID**: :ref:`GenericID`
- | ID of the notification.
+ | Notification identification
**Returns:**
- | **result**: str
- | Success message.
+ | str
+
+ .. code-block:: python
+
+ # If receive an error "Authorization Denied", check policy **Run User** / **Delete notification** in Access Management.
+ from tagoio_sdk import Resources
+ resources = Resources()
+ result = resources.run.notificationDelete("notification-id-123")
+ print(result) # Successfully Removed
-============
+
+===========
ssoSAMLInfo
-============
+===========
-Get the SAML Single Sign-On information for the account's RUN.
+Retrieves the SAML Single Sign-On configuration information for the Run environment.
+See: `Single Sign-On (SSO) `_
-============
+ **Returns:**
+
+ | :ref:`RunSAMLInfo`
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.ssoSAMLInfo()
+ print(result) # {'sp': {'entity_id': 'https://example.com', ...}, ...}
+
+
+===========
ssoSAMLEdit
-============
+===========
+
+Updates the SAML SSO configuration for the Run environment.
-Edit the SAML Single Sign-On metadata and mappings for the account's RUN.
+See: `Single Sign-On (SSO) `_
**Parameters:**
| **data**: :ref:`RunSAMLEditInfo`
- | Updated data for a RUN's SAML Single Sign-On configuration.
+ | SAML SSO configuration data
+
+ **Returns:**
+
+ | str
+ .. code-block:: python
-===================
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.ssoSAMLEdit({
+ "active": True,
+ "idp_metadata": "..."
+ })
+ print(result) # TagoIO Run SAML SSO Successfully Updated
+
+
+==================
createCustomDomain
-===================
+==================
-Create a TagoRUN custom domain for the profile.
+Creates a custom domain configuration for the Run environment.
+
+See: `Custom Domain Configuration `_
**Parameters:**
- | **profile_id**: str
- | ID of the profile
+ | **profile_id**: str
+ | Profile identification
-.. toctree::
+ | **customDomainData**: :ref:`CustomDomainCreate`
+ | Custom domain configuration data
- Run_Types
+ **Returns:**
+ | str
-================
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.createCustomDomain("profile-id-123", {
+ "domain": "app.mycompany.com"
+ })
+ print(result) # Custom domain created successfully
+
+
+===============
getCustomDomain
-================
+===============
+
+Retrieves the custom domain configuration for a Run profile.
+
+See: `Custom Domain Configuration `_
+
+ **Parameters:**
-Set details of TagoRun custom domain for the profile.
+ | **profile_id**: str
+ | Profile identification
- **Parameters**
+ **Returns:**
+
+ | :ref:`CustomDomainInfo`
+
+ .. code-block:: python
- | **profile_id**: str
- | ID of the profile
+ from tagoio_sdk import Resources
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.getCustomDomain("profile-id-123")
+ print(result) # {'domain': 'app.mycompany.com', 'verified': True, ...}
-===================
+
+==================
deleteCustomDomain
-===================
+==================
+
+Removes the custom domain configuration from a Run profile.
-Delete a TagoRUN custom domain for the profile.
+See: `Custom Domain Configuration `_
- **Parameters**
+ **Parameters:**
- | **profile_id**: str
- | ID of the profile
+ | **profile_id**: str
+ | Profile identification
+
+ **Returns:**
+ | str
-=======================
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.deleteCustomDomain("profile-id-123")
+ print(result) # Custom domain deleted successfully
+
+
+======================
regenerateCustomDomain
-=======================
+======================
+
+Regenerates the custom domain configuration for a Run profile.
-Regenerate a TagoRUN custom domain for the profile.
+See: `Custom Domain Configuration `_
- **Parameters**
+ **Parameters:**
- | **profile_id**: str
- | ID of the profile
+ | **profile_id**: str
+ | Profile identification
+
+ **Returns:**
+
+ | str
+
+ .. code-block:: python
+
+ from tagoio_sdk import Resources
+
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.regenerateCustomDomain("profile-id-123")
+ print(result) # Custom domain regenerated successfully
+
+
+.. toctree::
+
+ Run_Types
diff --git a/docs/source/index.rst b/docs/source/index.rst
index ab56705..50471cf 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -340,7 +340,7 @@ Support & Resources
🐛 **Issues & Bugs:** `GitHub Issues `_
-💬 **Help Center:** `TagoIO Support `_
+💬 **Help Center:** `TagoIO Support `_
🌐 **Platform:** `TagoIO Console `_
diff --git a/src/tagoio_sdk/modules/Resources/Dashboard_Widgets.py b/src/tagoio_sdk/modules/Resources/Dashboard_Widgets.py
new file mode 100644
index 0000000..26fa4b4
--- /dev/null
+++ b/src/tagoio_sdk/modules/Resources/Dashboard_Widgets.py
@@ -0,0 +1,376 @@
+from typing import Dict
+from typing import List
+from typing import Optional
+from typing import Union
+
+from tagoio_sdk.common.Common_Type import GenericID
+from tagoio_sdk.common.Common_Type import GenericToken
+from tagoio_sdk.common.tagoio_module import TagoIOModule
+from tagoio_sdk.modules.Resources.Dashboards_Type import EditDataModel
+from tagoio_sdk.modules.Resources.Dashboards_Type import EditDeviceResource
+from tagoio_sdk.modules.Resources.Dashboards_Type import EditResourceOptions
+from tagoio_sdk.modules.Resources.Dashboards_Type import GetDataModel
+from tagoio_sdk.modules.Resources.Dashboards_Type import PostDataModel
+from tagoio_sdk.modules.Resources.Dashboards_Type import WidgetInfo
+
+
+class Widgets(TagoIOModule):
+ def create(self, dashboardID: GenericID, widgetObj: WidgetInfo) -> Dict[str, GenericID]:
+ """
+ @description:
+ Creates a new widget for a specified dashboard with the given configuration.
+ After created, it is not added into the dashboard arrangement; it is necessary to edit
+ the dashboard to include it in the arrangement.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Create and Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.create("dashboard-id-123", {
+ "data": [{
+ "origin": "origin-id-123",
+ "query": "last_value",
+ "variables": ["temperature"]
+ }],
+ "display": {
+ "show_units": True,
+ "show_variables": True,
+ "variables": [{
+ "origin": "origin-id-123",
+ "variable": "temperature"
+ }]
+ },
+ "label": "Temperature",
+ "type": "display",
+ })
+ print(result) # {'widget': 'widget-id-456'}
+
+ # To add the widget size to the dashboard
+ # Before running this, make sure doesn't have more widgets in the dashboard.
+ resources.dashboards.edit("dashboard-id-123", {
+ "arrangement": [{"widget_id": result["widget"], "width": 1, "height": 2, "minW": 1, "minH": 2, "x": 0, "y": 0}]
+ })
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/dashboard/{dashboardID}/widget/",
+ "method": "POST",
+ "body": widgetObj,
+ }
+ )
+
+ return result
+
+ def edit(self, dashboardID: GenericID, widgetID: GenericID, data: Dict) -> str:
+ """
+ @description:
+ Updates an existing widget's configuration on a dashboard.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.edit("dashboard-id-123", "widget-id-456", {
+ "label": "Updated Temperature",
+ })
+ print(result) # Successfully Updated
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/dashboard/{dashboardID}/widget/{widgetID}",
+ "method": "PUT",
+ "body": data,
+ }
+ )
+
+ return result
+
+ def delete(self, dashboardID: GenericID, widgetID: GenericID) -> str:
+ """
+ @description:
+ Permanently removes a widget from a dashboard.
+ After deleted, it is not removed from the dashboard arrangement; it is necessary to edit
+ the dashboard to remove it from the arrangement.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Delete and Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.delete("dashboard-id-123", "widget-id-456")
+ print(result) # Successfully Removed
+
+ # To remove sizes from all widgets from a dashboard
+ # Before running this, make sure doesn't have more widgets in the dashboard.
+ resources.dashboards.edit("dashboard-id-123", {"arrangement": []})
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/dashboard/{dashboardID}/widget/{widgetID}",
+ "method": "DELETE",
+ }
+ )
+
+ return result
+
+ def info(self, dashboardID: GenericID, widgetID: GenericID) -> WidgetInfo:
+ """
+ @description:
+ Retrieves detailed information about a specific widget.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.info("dashboard-id-123", "widget-id-456")
+ print(result) # {'id': 'widget-id-456', 'data': [{'query': 'last_value', ...}, ...], ...}
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/dashboard/{dashboardID}/widget/{widgetID}",
+ "method": "GET",
+ }
+ )
+
+ return result
+
+ def getData(
+ self,
+ dashboardID: GenericID,
+ widgetID: GenericID,
+ params: Optional[GetDataModel] = None,
+ ) -> object:
+ """
+ @description:
+ Retrieves data or resource list for a specific widget based on the given parameters.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.getData("dashboard-id-123", "widget-id-456", {
+ "start_date": "2025-01-01",
+ "end_date": "2025-12-31",
+ "timezone": "UTC"
+ })
+ print(result) # {'widget': {'analysis_run': None, 'dashboard': '6791456f8b726c0009adccec', ...}, ...}
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/data/{dashboardID}/{widgetID}",
+ "method": "GET",
+ "params": params,
+ }
+ )
+
+ return result
+
+ def sendData(
+ self,
+ dashboardID: GenericID,
+ widgetID: GenericID,
+ data: Union[PostDataModel, List[PostDataModel]],
+ bypassBucket: bool = False,
+ ) -> object:
+ """
+ @description:
+ Sends new data values to be displayed in the widget.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.sendData("dashboard-id-123", "widget-id-456", {
+ "origin": "origin-id-123",
+ "variable": "temperature",
+ "value": 25.5,
+ "unit": "C"
+ })
+ print(result) # ['1 Data Added']
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/data/{dashboardID}/{widgetID}",
+ "method": "POST",
+ "params": {
+ "bypass_bucket": bypassBucket,
+ },
+ "body": data,
+ }
+ )
+
+ return result
+
+ def editData(
+ self,
+ dashboardID: GenericID,
+ widgetID: GenericID,
+ data: Union[EditDataModel, List[EditDataModel]],
+ bypassBucket: bool = False,
+ ) -> object:
+ """
+ @description:
+ Updates existing data values for a specific widget.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.editData("dashboard-id-123", "widget-id-456", {
+ "origin": "origin-id-123",
+ "id": "data-id-789",
+ "value": 25.5
+ })
+ print(result) # Device Data Updated
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/data/{dashboardID}/{widgetID}/data",
+ "method": "PUT",
+ "params": {
+ "bypass_bucket": bypassBucket,
+ },
+ "body": data,
+ }
+ )
+
+ return result
+
+ def deleteData(self, dashboardID: GenericID, widgetID: GenericID, idPairs: List[str]) -> str:
+ """
+ @description:
+ Removes multiple data items from the widget by pairs of data ID and resource ID.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.deleteData(
+ "dashboard-id",
+ "widget-id",
+ [
+ "data_1-id:device_A-id",
+ "data_2-id:device_A-id",
+ "data_3-id:device_B-id",
+ ]
+ )
+ print(result) # Successfully Removed
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/data/{dashboardID}/{widgetID}",
+ "method": "DELETE",
+ "params": {
+ "ids": idPairs,
+ },
+ }
+ )
+
+ return result
+
+ def editResource(
+ self,
+ dashboardID: GenericID,
+ widgetID: GenericID,
+ resourceData: Union[EditDeviceResource, List[EditDeviceResource]],
+ options: Optional[EditResourceOptions] = None,
+ ) -> object:
+ """
+ @description:
+ Updates resource values associated with the widget.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.editResource(
+ "dashboard-id-123",
+ "widget-id-456",
+ {
+ "device": "device-id-789",
+ "name": "Updated Device Name",
+ "active": True
+ },
+ {"identifier": "my-identifier"}
+ )
+ print(result) # Resource Updated
+ ```
+ """
+ if options is None:
+ options = {}
+
+ result = self.doRequest(
+ {
+ "path": f"/data/{dashboardID}/{widgetID}/resource",
+ "method": "PUT",
+ "params": {
+ "widget_exec": options.get("identifier"),
+ },
+ "body": resourceData,
+ }
+ )
+
+ return result
+
+ def tokenGenerate(self, dashboardID: GenericID, widgetID: GenericID) -> Dict[str, GenericToken]:
+ """
+ @description:
+ Generates a new authentication token for embedding a widget. Each call regenerates the token.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/15-dashboard-overview Dashboard Overview
+ https://docs.tago.io/docs/tagoio/widgets/ Widgets
+
+ @example:
+ ```python
+ resources = Resources()
+ result = resources.dashboards.widgets.tokenGenerate("dashboard-id-123", "widget-id-456")
+ print(result) # {'widget_token': 'widget-token-123'}
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/dashboard/{dashboardID}/widget/{widgetID}/token",
+ "method": "GET",
+ }
+ )
+
+ return result
diff --git a/src/tagoio_sdk/modules/Resources/Dashboards.py b/src/tagoio_sdk/modules/Resources/Dashboards.py
index 2704dc8..a18f8d2 100644
--- a/src/tagoio_sdk/modules/Resources/Dashboards.py
+++ b/src/tagoio_sdk/modules/Resources/Dashboards.py
@@ -1,3 +1,6 @@
+from typing import Any
+from typing import Dict
+from typing import List
from typing import Optional
from typing import TypedDict
@@ -5,6 +8,7 @@
from tagoio_sdk.common.Common_Type import GenericID
from tagoio_sdk.common.Common_Type import Query
from tagoio_sdk.common.tagoio_module import TagoIOModule
+from tagoio_sdk.modules.Resources.Dashboard_Widgets import Widgets
from tagoio_sdk.modules.Resources.Dashboards_Type import AnalysisRelated
from tagoio_sdk.modules.Resources.Dashboards_Type import DashboardCreateInfo
from tagoio_sdk.modules.Resources.Dashboards_Type import DashboardInfo
@@ -15,21 +19,26 @@
class Dashboards(TagoIOModule):
- def listDashboard(self, queryObj: Query = None) -> list[DashboardInfo]:
+ def listDashboard(self, queryObj: Optional[Query] = None) -> List[DashboardInfo]:
"""
- Retrieves a list with all dashboards from the account
+ @description:
+ Lists all dashboards from your application with pagination support.
- :default:
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
- queryObj: {
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.listDashboard({
"page": 1,
"fields": ["id", "name"],
- "filter": {},
- "amount": 20,
- "orderBy": ["label", "asc"],
- }
-
- :param queryObj Search query params
+ "amount": 10,
+ "orderBy": ["label", "asc"]
+ })
+ print(result) # [{'id': 'dashboard-id-123', 'label': 'My Dashboard', ...}, ...]
+ ```
"""
if queryObj is None:
@@ -58,14 +67,27 @@ def listDashboard(self, queryObj: Query = None) -> list[DashboardInfo]:
result = dateParserList(result, ["created_at", "updated_at", "last_access"])
return result
- class dashboard(TypedDict):
+ class CreateDashboardResponse(TypedDict):
dashboard: GenericID
- def create(self, dashboardObj: DashboardCreateInfo) -> dashboard:
+ def create(self, dashboardObj: DashboardCreateInfo) -> CreateDashboardResponse:
"""
- Create dashboard
-
- :param dashboardObj Dashboard object
+ @description:
+ Creates a new dashboard in your application.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Create** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.create({
+ "label": "My Dashboard",
+ "tags": [{"key": "type", "value": "monitoring"}]
+ })
+ print(result) # {'dashboard': 'dashboard-id-123'}
+ ```
"""
result = self.doRequest(
{
@@ -77,20 +99,30 @@ def create(self, dashboardObj: DashboardCreateInfo) -> dashboard:
return result
- def edit(self, dashboardID: GenericID, dashboardObj: DashboardInfo) -> str:
+ def edit(self, dashboardID: GenericID, dashboardObj: Dict[str, Any]) -> str:
"""
- Modify any property of the dashboards
-
- :param dashboardID Dashboard identification
- :param dashboardObj Dashboard Object with data to be replaced
+ @description:
+ Modifies an existing dashboard's properties.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.edit("dashboard-id-123", {
+ "label": "Updated Dashboard",
+ "active": False
+ })
+ print(result) # Successfully Updated
+ ```
"""
result = self.doRequest(
{
"path": f"/dashboard/{dashboardID}",
"method": "PUT",
- "body": {
- dashboardObj,
- },
+ "body": dashboardObj,
}
)
@@ -98,9 +130,19 @@ def edit(self, dashboardID: GenericID, dashboardObj: DashboardInfo) -> str:
def delete(self, dashboardID: GenericID) -> str:
"""
- Deletes an dashboard from the account
-
- :param dashboardID Dashboard identification
+ @description:
+ Deletes a dashboard from the application.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Delete** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.delete("dashboard-id-123")
+ print(result) # Successfully Removed
+ ```
"""
result = self.doRequest(
{
@@ -113,9 +155,19 @@ def delete(self, dashboardID: GenericID) -> str:
def info(self, dashboardID: GenericID) -> DashboardInfo:
"""
- Gets information about the dashboard
-
- :param dashboardID Dashboard identification
+ @description:
+ Retrieves detailed information about a specific dashboard.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ dashboard_info = resources.dashboards.info("dashboard-id-123")
+ print(dashboard_info) # {'id': 'dashboard-id-123', 'label': 'My Dashboard', ...}
+ ```
"""
result = self.doRequest(
{
@@ -127,22 +179,33 @@ def info(self, dashboardID: GenericID) -> DashboardInfo:
result = dateParser(result, ["created_at", "updated_at", "last_access"])
return result
- class duplicate(TypedDict):
+ class DuplicateDashboardResponse(TypedDict):
dashboard_id: str
message: str
- class dashboardObj(TypedDict):
- setup: Optional[any]
+ class DuplicateDashboardOptions(TypedDict):
+ setup: Optional[Any]
new_label: Optional[str]
def duplicate(
- self, dashboardID: GenericID, dashboardObj: Optional[dashboardObj] = None
- ) -> duplicate:
+ self,
+ dashboardID: GenericID,
+ dashboardObj: Optional[DuplicateDashboardOptions] = None,
+ ) -> DuplicateDashboardResponse:
"""
- Duplicate the dashboard to your own account
-
- :param dashboardID Dashboard identification
- :param dashboardObj Object with data of the duplicate dashboard
+ @description:
+ Creates a copy of an existing dashboard.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Duplicate** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.dashboards.duplicate("dashboard-id-123", {"new_label": "Copy of My Dashboard"})
+ print(result) # {'dashboard_id': 'new-dashboard-id', 'message': 'Dashboard duplicated successfully'}
+ ```
"""
result = self.doRequest(
{
@@ -154,14 +217,21 @@ def duplicate(
return result
- def getPublicKey(
- self, dashboardID: GenericID, expireTime: ExpireTimeOption = "never"
- ) -> PublicKeyResponse:
+ def getPublicKey(self, dashboardID: GenericID, expireTime: ExpireTimeOption = "never") -> PublicKeyResponse:
"""
- Generate a new public token for the dashboard
-
- :param dashboardID Dashboard identification
- :param expireTime Time when token will expire
+ @description:
+ Generates a new public access token for the dashboard.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy in Access Management.
+ ```python
+ resources = Resources()
+ public_key = resources.dashboards.getPublicKey("dashboard-id-123", "1day")
+ print(public_key) # {'token': 'token-id-123', 'expire_time': '2025-01-02T00:00:00.000Z'}
+ ```
"""
result = self.doRequest(
{
@@ -179,9 +249,19 @@ def getPublicKey(
def listDevicesRelated(self, dashboardID: GenericID) -> list[DevicesRelated]:
"""
- Get list of devices related with dashboard
-
- :param dashboardID Dashboard identification
+ @description:
+ Lists all devices associated with the dashboard.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Related devices** in Access Management.
+ ```python
+ resources = Resources()
+ devices = resources.dashboards.listDevicesRelated("dashboard-id-123")
+ print(devices) # [{'id': 'device-id-123'}, {'id': 'device-id-xyz'}, ...]
+ ```
"""
result = self.doRequest(
{
@@ -194,9 +274,19 @@ def listDevicesRelated(self, dashboardID: GenericID) -> list[DevicesRelated]:
def listAnalysisRelated(self, dashboardID: GenericID) -> list[AnalysisRelated]:
"""
- Get list of analysis related with a dashboard
-
- :param dashboardID Dashboard identification
+ @description:
+ Lists all analyses associated with a dashboard.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Dashboard** / **Related analysis** in Access Management.
+ ```python
+ resources = Resources()
+ analyses = resources.dashboards.listAnalysisRelated("dashboard-id-123")
+ print(analyses) # [{'id': 'analysis-id-123', 'name': 'Analysis #1'}, ...]
+ ```
"""
result = self.doRequest(
{
@@ -212,15 +302,26 @@ def runWidgetHeaderButtonAnalysis(
analysisID: GenericID,
dashboardID: GenericID,
widgetID: GenericID,
- scope: Optional[any] = None,
+ scope: Optional[Dict[str, Any]] = None,
) -> str:
"""
- Runs an analysis located in a widget's header button
-
- :param analysisID The id of the analysis to run
- :param dashboardID The id of the dashboard that contains the widget
- :param widgetID The id of the widget that contains the header button
- :param scope Data to send to the analysis
+ @description:
+ Executes an analysis from a widget's header button.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/dashboards/ Dashboard Overview
+
+ @example:
+ ```python
+ resources = Resources()
+ result = resources.dashboards.runWidgetHeaderButtonAnalysis(
+ "analysis-id-123",
+ "dashboard-id-456",
+ "widget-id-789",
+ {"custom_data": "value"}
+ )
+ print(result) # Analysis executed successfully
+ ```
"""
if scope is None:
scope = {}
@@ -228,8 +329,12 @@ def runWidgetHeaderButtonAnalysis(
{
"path": f"/analysis/{analysisID}/run/{dashboardID}/{widgetID}",
"method": "POST",
- "body": scope,
+ "body": {"scope": scope},
}
)
return result
+
+ def __init__(self, params):
+ super().__init__(params)
+ self.widgets = Widgets(params)
diff --git a/src/tagoio_sdk/modules/Resources/Dashboards_Type.py b/src/tagoio_sdk/modules/Resources/Dashboards_Type.py
index a46f366..93835b8 100644
--- a/src/tagoio_sdk/modules/Resources/Dashboards_Type.py
+++ b/src/tagoio_sdk/modules/Resources/Dashboards_Type.py
@@ -53,7 +53,7 @@ class shared(TypedDict):
allow_share: bool
-class blueprint_devices(TypedDict):
+class BlueprintDeviceConfig(TypedDict):
conditions: list[conditions]
name: str
id: str
@@ -74,10 +74,8 @@ class DashboardInfo(TypedDict):
background: any
type: str
blueprint_device_behavior: Literal["more_than_one", "always"]
- blueprint_selector_behavior: Literal[
- "open", "closed", "always_open", "always_closed"
- ]
- blueprint_devices: blueprint_devices
+ blueprint_selector_behavior: Literal["open", "closed", "always_open", "always_closed"]
+ blueprint_devices: BlueprintDeviceConfig
theme: any
setup: any
shared: shared
@@ -159,7 +157,7 @@ class PostDataModel(TypedDict):
variable: str
-class blueprint_devices(TypedDict):
+class BlueprintDeviceOrigin(TypedDict):
origin: GenericID
id: GenericID
bucket: Optional[GenericID]
@@ -173,7 +171,7 @@ class widgetOverwrite(TypedDict):
class GetDataModel(TypedDict):
overwrite: Optional[widgetOverwrite]
- blueprint_devices: Optional[list[blueprint_devices]]
+ blueprint_devices: Optional[list[BlueprintDeviceOrigin]]
page: Optional[Union[int, float]]
amount: Optional[Union[int, float]]
@@ -183,7 +181,9 @@ class PublicKeyResponse(TypedDict):
expire_time: ExpireTimeOption
-EditDataModel = PostDataModel and {id: GenericID}
+class EditDataModel(PostDataModel):
+ id: GenericID
+
PublicKeyResponse = PublicKeyResponse
diff --git a/src/tagoio_sdk/modules/Resources/Device_Type.py b/src/tagoio_sdk/modules/Resources/Device_Type.py
index ee56efc..6b87af0 100644
--- a/src/tagoio_sdk/modules/Resources/Device_Type.py
+++ b/src/tagoio_sdk/modules/Resources/Device_Type.py
@@ -488,3 +488,60 @@ class ListDeviceTokenQuery(TypedDict):
"""
Tuple with a field and an order
"""
+
+
+class DeviceChunkData(TypedDict):
+ id: str
+ """
+ Chunk ID in format 'from_to' (Unix timestamps).
+ """
+ from_date: str
+ """
+ Start date of the chunk (ISO 8601).
+ """
+ to_date: str
+ """
+ End date of the chunk (ISO 8601).
+ """
+ amount: Union[int, float]
+ """
+ Amount of data records in the chunk.
+ """
+
+
+class DeviceDataBackup(TypedDict):
+ deviceID: GenericID
+ """
+ Device ID.
+ """
+ file_address: str
+ """
+ File path in TagoIO Files where backup will be saved.
+ Can use template variables: $DEVICE$, $CHUNK$, $FROM$, $TO$, $TIMESTAMP$.
+ """
+ headers: Optional[bool]
+ """
+ Include CSV headers in the exported file.
+ """
+
+
+class DeviceDataBackupResponse(TypedDict):
+ file_address: str
+ """
+ Final file path where the backup was saved.
+ """
+ chunk_id: Optional[str]
+ """
+ Chunk ID if backup was for a specific chunk.
+ """
+
+
+class DeviceDataRestore(TypedDict):
+ deviceID: GenericID
+ """
+ Device ID.
+ """
+ file_address: str
+ """
+ File path in TagoIO Files to restore data from (CSV format).
+ """
diff --git a/src/tagoio_sdk/modules/Resources/Devices.py b/src/tagoio_sdk/modules/Resources/Devices.py
index 60782eb..7292ca3 100644
--- a/src/tagoio_sdk/modules/Resources/Devices.py
+++ b/src/tagoio_sdk/modules/Resources/Devices.py
@@ -1,3 +1,4 @@
+from typing import List
from typing import Optional
from typing import Union
@@ -11,8 +12,12 @@
from tagoio_sdk.modules.Device.Device_Type import DataQuery
from tagoio_sdk.modules.Device.Device_Type import DeviceInfo
from tagoio_sdk.modules.Resources.Device_Type import ConfigurationParams
+from tagoio_sdk.modules.Resources.Device_Type import DeviceChunkData
from tagoio_sdk.modules.Resources.Device_Type import DeviceCreateInfo
from tagoio_sdk.modules.Resources.Device_Type import DeviceCreateResponse
+from tagoio_sdk.modules.Resources.Device_Type import DeviceDataBackup
+from tagoio_sdk.modules.Resources.Device_Type import DeviceDataBackupResponse
+from tagoio_sdk.modules.Resources.Device_Type import DeviceDataRestore
from tagoio_sdk.modules.Resources.Device_Type import DeviceEditInfo
from tagoio_sdk.modules.Resources.Device_Type import DeviceListItem
from tagoio_sdk.modules.Resources.Device_Type import DeviceQuery
@@ -26,20 +31,25 @@
class Devices(TagoIOModule):
def listDevice(self, queryObj: DeviceQuery = None) -> list[DeviceListItem]:
"""
- Retrieves a list with all devices from the account
+ @description:
+ Retrieves a list of all devices from the account with optional filtering and pagination.
- :default:
+ @see:
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
- queryObj: {
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ devices = resources.devices.listDevice({
"page": 1,
- "fields": ["id", "name"],
- "filter": {},
"amount": 20,
- "orderBy": ["name", "asc"],
- "resolveBucketName": False
- }
-
- :param DeviceQuery queryObj: Search query params
+ "fields": ["id", "name", "active"],
+ "filter": {"name": "Temperature*"},
+ "orderBy": ["name", "asc"]
+ })
+ print(devices) # [{'id': 'device-id-123', 'name': 'Temperature Sensor', ...}]
+ ```
"""
if queryObj is None:
queryObj = {}
@@ -80,9 +90,28 @@ def listDevice(self, queryObj: DeviceQuery = None) -> list[DeviceListItem]:
def create(self, deviceObj: DeviceCreateInfo) -> DeviceCreateResponse:
"""
- Generates and retrieves a new action from the Device
-
- :param DeviceCreateInfo deviceObj: Object data to create new device
+ @description:
+ Creates a new device in the account with specified configuration and returns device credentials.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
+ https://help.tago.io/portal/en/kb/articles/481-device-types Device Types
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Create** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.create({
+ "name": "Temperature Sensor",
+ "network": "network-id-123",
+ "connector": "connector-id-456",
+ "type": "immutable",
+ "chunk_period": "month",
+ "chunk_retention": 6,
+ "active": True
+ })
+ print(result) # {'device_id': '...', 'bucket_id': '...', 'token': '...'}
+ ```
"""
result = self.doRequest(
{
@@ -95,11 +124,23 @@ def create(self, deviceObj: DeviceCreateInfo) -> DeviceCreateResponse:
def edit(self, deviceID: GenericID, deviceObj: DeviceEditInfo) -> str:
"""
- Modify any property of the device
+ @description:
+ Modifies any property of an existing device.
- :param GenericID deviceID: Device ID
+ @see:
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
- :param DeviceEditInfo deviceObj: Device object with fields to replace
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.edit("device-id-123", {
+ "name": "Updated Sensor Name",
+ "active": False,
+ "tags": [{"key": "location", "value": "warehouse"}]
+ })
+ print(result) # Successfully Updated
+ ```
"""
result = self.doRequest(
{
@@ -112,9 +153,19 @@ def edit(self, deviceID: GenericID, deviceObj: DeviceEditInfo) -> str:
def delete(self, deviceID: GenericID) -> str:
"""
- Deletes an device from the account
+ @description:
+ Permanently deletes a device from the account along with all its data.
- :param GenericID deviceID: Device ID
+ @see:
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Delete** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.delete("device-id-123")
+ print(result) # Successfully Removed
+ ```
"""
result = self.doRequest(
{
@@ -126,9 +177,19 @@ def delete(self, deviceID: GenericID) -> str:
def info(self, deviceID: GenericID) -> DeviceInfo:
"""
- Get Info of the Device
+ @description:
+ Retrieves detailed information about a specific device.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/478-devices Devices Overview
- :param GenericID deviceID: Device ID
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ device_info = resources.devices.info("device-id-123")
+ print(device_info) # {'id': '...', 'name': '...', 'type': 'mutable', ...}
+ ```
"""
result = self.doRequest(
{
@@ -157,13 +218,30 @@ def paramSet(
paramID: Optional[GenericID] = None,
) -> str:
"""
- Create or edit param for the Device
-
- :param deviceID Device ID
-
- :param configObj Configuration Data
-
- :param paramID Parameter ID
+ @description:
+ Creates new configuration parameters or updates existing ones for a device.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/configuration-parameters Configuration Parameters
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ # Create new parameter
+ result = resources.devices.paramSet("device-id-123", {
+ "key": "threshold",
+ "value": "25.5",
+ "sent": False
+ })
+ # Update existing parameter
+ result = resources.devices.paramSet("device-id-123", {
+ "key": "threshold",
+ "value": "30.0",
+ "sent": False
+ }, "param-id-456")
+ print(result) # Successfully Updated
+ ```
"""
body = configObj
if paramID and not isinstance(configObj, list):
@@ -182,32 +260,49 @@ def paramSet(
return result
- def paramList(
- self, deviceID: GenericID, sentStatus: bool = None
- ) -> list[ConfigurationParams]:
+ def paramList(self, deviceID: GenericID, sentStatus: bool = None) -> list[ConfigurationParams]:
"""
- List Params for the Device
+ @description:
+ Retrieves a list of configuration parameters for a device.
- :param GenericID deviceID: Device ID
+ @see:
+ https://help.tago.io/portal/en/kb/articles/configuration-parameters Configuration Parameters
- :param bool sentStatus: True return only sent=true, False return only sent=false
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ # Get all parameters
+ params = resources.devices.paramList("device-id-123")
+ # Get only sent parameters
+ sent_params = resources.devices.paramList("device-id-123", sentStatus=True)
+ print(params) # [{'id': '...', 'key': 'threshold', 'value': '25.5', 'sent': False}]
+ ```
"""
result = self.doRequest(
{
"path": f"/device/{deviceID}/params",
"method": "GET",
- "params": {"sent_status": sentStatus},
+ "params": {"sent_status": str(sentStatus).lower() if sentStatus is not None else None},
}
)
return result
def paramRemove(self, deviceID: GenericID, paramID: GenericID) -> str:
"""
- Remove param for the Device
+ @description:
+ Removes a specific configuration parameter from a device.
- :param GenericID deviceID: Device ID
+ @see:
+ https://help.tago.io/portal/en/kb/articles/configuration-parameters Configuration Parameters
- :param GenericID paramID: Parameter ID
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.paramRemove("device-id-123", "param-id-456")
+ print(result) # Successfully Removed
+ ```
"""
result = self.doRequest(
{
@@ -223,21 +318,24 @@ def tokenList(
queryObj: ListDeviceTokenQuery = None,
) -> list[DeviceTokenDataList]:
"""
- Retrieves a list of all tokens
+ @description:
+ Retrieves a list of all authentication tokens for a device with optional filtering.
- :default:
+ @see:
+ https://help.tago.io/portal/en/kb/articles/495-access-tokens Device Tokens
- queryObj: {
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ tokens = resources.devices.tokenList("device-id-123", {
"page": 1,
- "fields": ["name", "token", "permission"],
- "filter": {},
"amount": 20,
- "orderBy": ["created_at", "desc"],
- }
-
- :param GenericID deviceID: Device ID
-
- :param ListDeviceTokenQuery queryObj: Search query params
+ "fields": ["name", "token", "permission"],
+ "orderBy": ["created_at", "desc"]
+ })
+ print(tokens) # [{'name': 'Default Token', 'token': '...', 'permission': 'full', ...}]
+ ```
"""
if queryObj is None:
@@ -262,21 +360,29 @@ def tokenList(
},
}
)
- result = dateParserList(
- result, ["created_at", "expire_time"]
- )
+ result = dateParserList(result, ["created_at", "expire_time"])
return result
- def tokenCreate(
- self, deviceID: GenericID, tokenParams: TokenData
- ) -> TokenCreateResponse:
+ def tokenCreate(self, deviceID: GenericID, tokenParams: TokenData) -> TokenCreateResponse:
"""
- Generates and retrieves a new token
+ @description:
+ Generates and retrieves a new authentication token for a device.
- :param deviceID: Device ID
+ @see:
+ https://help.tago.io/portal/en/kb/articles/495-access-tokens Device Tokens
- :param tokenParams: Params for new token
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Create Token** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.tokenCreate("device-id-123", {
+ "name": "Production Token",
+ "permission": "write",
+ "expire_time": "never"
+ })
+ print(result) # {'token': 'new-token-value', 'expire_date': None}
+ ```
"""
result = self.doRequest(
{
@@ -290,9 +396,19 @@ def tokenCreate(
def tokenDelete(self, token: GenericToken) -> str:
"""
- Delete a token
+ @description:
+ Permanently deletes an authentication token.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/495-access-tokens Device Tokens
- :param GenericToken token: Token
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Delete Token** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.tokenDelete("token-to-delete")
+ print(result) # Successfully Removed
+ ```
"""
result = self.doRequest(
{
@@ -302,25 +418,27 @@ def tokenDelete(self, token: GenericToken) -> str:
)
return result
- def getDeviceData(
- self, deviceID: GenericID, queryParams: DataQuery = None
- ) -> list[Data]:
+ def getDeviceData(self, deviceID: GenericID, queryParams: DataQuery = None) -> list[Data]:
"""
- Get data from all variables in the device.
-
- :param deviceID: Device ID.
+ @description:
+ Retrieves data from all variables in the device with optional query filters.
- :param queryParams: Query parameters to filter the results.
+ @see:
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
- :rtype: Array with the data values stored in the device.
-
- :example:
-
- myDevice = Account({ "token": "my_device_token" })
-
- result = myAccount.devices.getDeviceData(
- "Device Id", {"variables": "location"}
- )
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ # Get all data
+ data = resources.devices.getDeviceData("device-id-123")
+ # Get specific variable data
+ temp_data = resources.devices.getDeviceData("device-id-123", {
+ "variables": ["temperature"],
+ "qty": 10
+ })
+ print(temp_data) # [{'variable': 'temperature', 'value': 25.5, 'time': '...', ...}]
+ ```
"""
if queryParams is None:
queryParams = {}
@@ -335,11 +453,19 @@ def getDeviceData(
def emptyDeviceData(self, deviceID: GenericID) -> str:
"""
- Empty all data in a device.
+ @description:
+ Permanently removes all data from a device. This operation cannot be undone.
- :param GenericID deviceID: Device ID.
+ @see:
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
- :rtype: Success message.
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.emptyDeviceData("device-id-123")
+ print(result) # All data has been removed
+ ```
"""
result = self.doRequest(
{
@@ -349,110 +475,260 @@ def emptyDeviceData(self, deviceID: GenericID) -> str:
)
return result
- def sendDeviceData(
- self, deviceID: GenericID, data: Union[DataCreate, list[DataCreate]]
- ) -> str:
+ def sendDeviceData(self, deviceID: GenericID, data: Union[DataCreate, list[DataCreate]]) -> str:
+ """
+ @description:
+ Sends data to a device. Accepts a single data object or an array of data objects.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.sendDeviceData("device-id-123", {
+ "variable": "temperature",
+ "value": 25.5,
+ "unit": "°C",
+ "time": "2025-01-09 13:44:33",
+ "location": {"lat": 42.2974279, "lng": -85.628292}
+ })
+ # Send multiple data points
+ result = resources.devices.sendDeviceData("device-id-123", [
+ {"variable": "temperature", "value": 25.5},
+ {"variable": "humidity", "value": 60}
+ ])
+ print(result) # Successfully Inserted
+ ```
"""
- Send data to a device.
+ result = self.doRequest(
+ {
+ "path": f"/device/{deviceID}/data",
+ "method": "POST",
+ "body": data,
+ }
+ )
- :param GenericID deviceID: Device ID.
+ return result
- :param DataCreate data: An array or one object with data to be send to TagoIO.
+ def editDeviceData(self, deviceID: GenericID, updatedData: Union[DataEdit, list[DataEdit]]) -> str:
+ """
+ @description:
+ Modifies existing data records in a device. Requires the data record ID.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.editDeviceData("device-id-123", {
+ "id": "data-record-id",
+ "value": 30.0,
+ "unit": "°F"
+ })
+ # Edit multiple records
+ result = resources.devices.editDeviceData("device-id-123", [
+ {"id": "record-1-id", "value": 25.5},
+ {"id": "record-2-id", "value": 65}
+ ])
+ print(result) # Device Data Updated
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/device/{deviceID}/data",
+ "method": "PUT",
+ "body": updatedData,
+ }
+ )
- :rtype: Success message.
+ return result
- Example::
- ```python
- # Example of using the function
- resources = Resource()
- resource.devices.sendDeviceData("myDeviceID", {
- "variable": "temperature",
- "unit": "F",
- "value": 55,
- "time": "2015-11-03 13:44:33",
- "location": { "lat": 42.2974279, "lng": -85.628292 },
- })
- ```
+ def deleteDeviceData(self, deviceID: GenericID, queryParam: DataQuery = None) -> str:
+ """
+ @description:
+ Deletes data from a device based on specified query parameters.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ # Delete specific records by ID
+ result = resources.devices.deleteDeviceData("device-id-123", {
+ "ids": ["record-id-1", "record-id-2"]
+ })
+ # Delete by variable
+ result = resources.devices.deleteDeviceData("device-id-123", {
+ "variables": ["old_sensor"],
+ "qty": 100
+ })
+ print(result) # Successfully Removed
+ ```
"""
+ if queryParam is None:
+ queryParam = {}
result = self.doRequest(
{
"path": f"/device/{deviceID}/data",
- "method": "POST",
- "body": data,
+ "method": "DELETE",
+ "params": queryParam,
}
)
return result
- def editDeviceData(
- self, deviceID: GenericID, updatedData: Union[DataEdit, list[DataEdit]]
- ) -> str:
+ def amount(self, deviceID: GenericID) -> Union[int, float]:
"""
- Edit data in a device.
+ @description:
+ Gets the amount of data stored in a device.
- :param GenericID deviceID: Device ID.
+ @see:
+ https://help.tago.io/portal/en/kb/articles/device-data Device Data Management
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ amount = resources.devices.amount("device-id-123")
+ print(amount) # 15234
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/device/{deviceID}/data_amount",
+ "method": "GET",
+ }
+ )
+ return result
- :param DataEdit data: A single or an array of updated data records.
+ def getChunk(self, deviceID: GenericID) -> List[DeviceChunkData]:
+ """
+ @description:
+ Retrieves chunk information from an immutable device.
- :rtype: Success message.
+ @see:
+ https://help.tago.io/portal/en/kb/articles/chunk-management Chunk Management
- Example::
- ```python
- # Example of using the function
- resources = Resource()
- resource.devices.editDeviceData("myDeviceID", {"id": "idOfTheRecord", "value": "new value", "unit": "new unit"})
- ```
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Manage chunks** in Access Management.
+ ```python
+ resources = Resources()
+ chunks = resources.devices.getChunk("device-id-123")
+ print(chunks) # [{'amount': 0, 'id': 'chunk-id-123', 'from_date': '2025-01-09T00:00:00.000+00:00', ...}]
+ ```
"""
result = self.doRequest(
{
- "path": f"/device/{deviceID}/data",
- "method": "PUT",
- "body": updatedData,
+ "path": f"/device/{deviceID}/chunk",
+ "method": "GET",
}
)
return result
- def deleteDeviceData(
- self, deviceID: GenericID, queryParam: DataQuery = None
- ) -> str:
+ def deleteChunk(self, deviceID: GenericID, chunkID: GenericID) -> str:
"""
- Delete data from a device.
-
- :param GenericID deviceID: Device ID.
-
- :param DataQuery queryParam: Parameters to specify what should be deleted on the device's data.
+ @description:
+ Deletes a chunk from an immutable device.
- :rtype: Success message.
+ @see:
+ https://help.tago.io/portal/en/kb/articles/chunk-management#Delete_chunks Delete Chunks
- Example::
- ```python
- # Example of using the function
- resources = Resource()
- resource.devices.deleteDeviceData("myDeviceID", {"ids": ["recordIdToDelete", "anotherRecordIdToDelete" ]})
- ```
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Manage chunks** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.deleteChunk("device-id-123", "chunk-id-123")
+ print(result) # Chunk chunk-id-123 deleted
+ ```
"""
- if queryParam is None:
- queryParam = {}
result = self.doRequest(
{
- "path": f"/device/{deviceID}/data",
+ "path": f"/device/{deviceID}/chunk/{chunkID}",
"method": "DELETE",
- "params": queryParam,
}
)
return result
- def amount(self, deviceID: GenericID) -> Union[int, float]:
+ def dataBackup(self, params: DeviceDataBackup, chunkID: Optional[GenericID] = None) -> DeviceDataBackupResponse:
+ """
+ @description:
+ Schedule to export the device's data to TagoIO Files.
+ For mutable devices, exports all data. For immutable devices with chunkID, exports specific chunk.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/55-data-export Data Export
+ https://help.tago.io/portal/en/kb/articles/device-data#Backing_Up_Data Backing Up Data
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Export Data** in Access Management.
+ ```python
+ resources = Resources()
+ import time
+ timestamp = int(time.time())
+ result = resources.devices.dataBackup({
+ "deviceID": "device-id-123",
+ "file_address": f"/backups/device-id-123/{timestamp}",
+ "headers": True
+ })
+ print(result) # {'file_address': 'backups/device-id-123/1736433519380.csv'}
+ ```
+ """
+ body = {
+ "chunk_id": chunkID,
+ "headers": params.get("headers"),
+ "file_address": params.get("file_address"),
+ }
+
+ path = f"/device/{params['deviceID']}/chunk/backup" if chunkID else f"/device/{params['deviceID']}/data/backup"
+
+ result = self.doRequest(
+ {
+ "path": path,
+ "method": "POST",
+ "body": body,
+ }
+ )
+
+ return result
+
+ def dataRestore(self, params: DeviceDataRestore) -> str:
"""
- Get Amount of data stored in the Device
- :param deviceID: Device ID
+ @description:
+ Restores data to a device from a CSV file in TagoIO Files.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/device-data#Importing Importing Device Data
+ https://api.docs.tago.io/#7ebca255-6c38-43d3-97d0-9b62155f202e Import Data API
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Device** / **Import Data** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.devices.dataRestore({
+ "deviceID": "device-id-123",
+ "file_address": "/backups/backup.csv"
+ })
+ print(result) # Data import added to the queue successfully!
+ ```
"""
+ body = {
+ "file_address": params.get("file_address"),
+ }
+
result = self.doRequest(
{
- "path": f"/device/{deviceID}/data_amount",
- "method": "GET",
+ "path": f"/device/{params['deviceID']}/data/restore",
+ "method": "POST",
+ "body": body,
}
)
+
return result
diff --git a/src/tagoio_sdk/modules/Resources/IntegrationNetwork.py b/src/tagoio_sdk/modules/Resources/IntegrationNetwork.py
index b5e6188..8dc9fcc 100644
--- a/src/tagoio_sdk/modules/Resources/IntegrationNetwork.py
+++ b/src/tagoio_sdk/modules/Resources/IntegrationNetwork.py
@@ -1,26 +1,48 @@
+from typing import Dict
+from typing import List
+from typing import Optional
+
from tagoio_sdk.common.Common_Type import GenericID
-from tagoio_sdk.common.Common_Type import Query
+from tagoio_sdk.common.Common_Type import GenericToken
+from tagoio_sdk.common.Common_Type import TokenCreateResponse
+from tagoio_sdk.common.Common_Type import TokenData
from tagoio_sdk.common.tagoio_module import TagoIOModule
+from tagoio_sdk.modules.Resources.IntegrationNetworkType import ListTokenQuery
+from tagoio_sdk.modules.Resources.IntegrationNetworkType import NetworkCreateInfo
from tagoio_sdk.modules.Resources.IntegrationNetworkType import NetworkInfo
+from tagoio_sdk.modules.Resources.IntegrationNetworkType import NetworkQuery
+from tagoio_sdk.modules.Resources.IntegrationNetworkType import NetworkTokenInfo
+from tagoio_sdk.modules.Utils.dateParser import dateParser
+from tagoio_sdk.modules.Utils.dateParser import dateParserList
class Networks(TagoIOModule):
- def listNetwork(self, queryObj: Query = None) -> list[NetworkInfo]:
+ def listNetwork(self, queryObj: Optional[NetworkQuery] = None) -> List[NetworkInfo]:
"""
- Retrieves a list with all networks from the account
+ @description:
+ Retrieves a list of all networks from the account with pagination support.
+ Use this to retrieve and manage networks in your application.
- :default:
- fields: ["id", "name"]
+ @see:
+ https://docs.tago.io/docs/tagoio/integrations/general/creating-a-network-integration Network Integration
- :param fields Fields to be returned
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ networks = resources.integration.networks.listNetwork({
+ "page": 1,
+ "fields": ["id", "name"],
+ "amount": 20,
+ "orderBy": ["name", "asc"]
+ })
+ print(networks) # [{'id': 'network-id-123', 'name': 'My Network', ...}]
+ ```
"""
+ queryObj = queryObj or {}
- if queryObj is None:
- queryObj = {}
if "orderBy" in queryObj:
- firstArgument = queryObj["orderBy"][0]
- secondArgument = queryObj["orderBy"][1]
- orderBy = f"{firstArgument},{secondArgument}"
+ orderBy = f"{queryObj['orderBy'][0]},{queryObj['orderBy'][1]}"
else:
orderBy = "name,asc"
@@ -29,10 +51,10 @@ def listNetwork(self, queryObj: Query = None) -> list[NetworkInfo]:
"path": "/integration/network",
"method": "GET",
"params": {
- "page": queryObj.get("page") or 1,
- "fields": queryObj.get("fields") or ["id", "name"],
- "filter": queryObj.get("filter") or {},
- "amount": queryObj.get("amount") or 20,
+ "page": queryObj.get("page", 1),
+ "fields": queryObj.get("fields", ["id", "name"]),
+ "filter": queryObj.get("filter", {}),
+ "amount": queryObj.get("amount", 20),
"orderBy": orderBy,
},
}
@@ -40,19 +62,25 @@ def listNetwork(self, queryObj: Query = None) -> list[NetworkInfo]:
return result
- def info(self, networkID: GenericID, fields: NetworkInfo = None) -> NetworkInfo:
+ def info(self, networkID: GenericID, fields: Optional[List[str]] = None) -> NetworkInfo:
"""
- Retrieves the information of the network.
+ @description:
+ Retrieves detailed information about a specific network.
- :default:
- fields: ["id", "name"]
+ @see:
+ https://docs.tago.io/docs/tagoio/integrations/general/creating-a-network-integration Network Integration
- :param networkID Network ID
- :param fields Fields to be returned
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ network_info = resources.integration.networks.info("network-id-123")
+ print(network_info) # {'id': '...', 'name': 'My Network', ...}
+ ```
"""
-
if fields is None:
fields = ["id", "name"]
+
result = self.doRequest(
{
"path": f"/integration/network/{networkID}",
@@ -64,3 +92,186 @@ def info(self, networkID: GenericID, fields: NetworkInfo = None) -> NetworkInfo:
)
return result
+
+ def create(self, networkObj: NetworkCreateInfo) -> Dict[str, str]:
+ """
+ @description:
+ Creates a new integration network in the account.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/integrations/general/creating-a-network-integration#create-a-new-integration Creating a Network Integration
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Create** in Access Management.
+ ```python
+ resources = Resources()
+ new_network = resources.integration.networks.create({
+ "name": "My Custom Network",
+ "description": "Custom integration network",
+ "middleware_endpoint": "https://my-middleware.com/endpoint",
+ "public": False
+ })
+ print(new_network) # {'network': 'network-id-123'}
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": "/integration/network",
+ "method": "POST",
+ "body": networkObj,
+ }
+ )
+
+ return result
+
+ def edit(self, networkID: GenericID, networkObj: NetworkCreateInfo) -> str:
+ """
+ @description:
+ Modifies any property of an existing network.
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.integration.networks.edit("network-id-123", {
+ "name": "Updated Network Name",
+ "description": "Updated description",
+ "public": True
+ })
+ print(result) # Successfully Updated
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/integration/network/{networkID}",
+ "method": "PUT",
+ "body": networkObj,
+ }
+ )
+
+ return result
+
+ def delete(self, networkID: GenericID) -> str:
+ """
+ @description:
+ Permanently deletes a network from the account.
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Delete** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.integration.networks.delete("network-id-123")
+ print(result) # Successfully Removed
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/integration/network/{networkID}",
+ "method": "DELETE",
+ }
+ )
+
+ return result
+
+ def tokenList(self, networkID: GenericID, queryObj: Optional[ListTokenQuery] = None) -> List[NetworkTokenInfo]:
+ """
+ @description:
+ Retrieves a list of all authentication tokens for a network with optional filtering.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/integrations/general/creating-a-network-integration#tokens-and-getting-devices Tokens and Getting Devices
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ tokens = resources.integration.networks.tokenList("network-id-123", {
+ "page": 1,
+ "amount": 20,
+ "fields": ["name", "token", "permission"],
+ "orderBy": ["created_at", "desc"]
+ })
+ print(tokens) # [{'name': 'Default Token', 'token': '...', 'permission': 'full', ...}]
+ ```
+ """
+ queryObj = queryObj or {}
+
+ if "orderBy" in queryObj:
+ orderBy = f"{queryObj['orderBy'][0]},{queryObj['orderBy'][1]}"
+ else:
+ orderBy = "created_at,desc"
+
+ result = self.doRequest(
+ {
+ "path": f"/integration/network/token/{networkID}",
+ "method": "GET",
+ "params": {
+ "page": queryObj.get("page", 1),
+ "fields": queryObj.get("fields", ["name", "token", "permission"]),
+ "filter": queryObj.get("filter", {}),
+ "amount": queryObj.get("amount", 20),
+ "orderBy": orderBy,
+ },
+ }
+ )
+
+ result = dateParserList(result, ["created_at", "updated_at"])
+
+ return result
+
+ def tokenCreate(self, networkID: GenericID, tokenParams: TokenData) -> TokenCreateResponse:
+ """
+ @description:
+ Generates and retrieves a new authentication token for a network.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/integrations/general/creating-a-network-integration#tokens-and-getting-devices Tokens and Getting Devices
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Create Token** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.integration.networks.tokenCreate("network-id-123", {
+ "name": "Production Token",
+ "permission": "write",
+ "expire_time": "never"
+ })
+ print(result) # {'token': 'new-token-value', 'expire_date': None}
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": "/integration/network/token",
+ "method": "POST",
+ "body": {"network": networkID, **tokenParams},
+ }
+ )
+
+ result = dateParser(result, ["expire_date"])
+
+ return result
+
+ def tokenDelete(self, token: GenericToken) -> str:
+ """
+ @description:
+ Permanently deletes an authentication token.
+
+ @see:
+ https://docs.tago.io/docs/tagoio/integrations/general/creating-a-network-integration#tokens-and-getting-devices Tokens and Getting Devices
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Integration Network** / **Delete Token** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.integration.networks.tokenDelete("token-to-delete")
+ print(result) # Successfully Removed
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/integration/network/token/{token}",
+ "method": "DELETE",
+ }
+ )
+
+ return result
diff --git a/src/tagoio_sdk/modules/Resources/IntegrationNetworkType.py b/src/tagoio_sdk/modules/Resources/IntegrationNetworkType.py
index 23f58fc..df4de38 100644
--- a/src/tagoio_sdk/modules/Resources/IntegrationNetworkType.py
+++ b/src/tagoio_sdk/modules/Resources/IntegrationNetworkType.py
@@ -58,8 +58,33 @@ class NetworkInfo(NetworkCreateInfo):
serial_number: Optional[serial_number]
+class NetworkTokenInfo(TypedDict):
+ token: str
+ network: GenericID
+ name: str
+ permission: str
+ created_at: datetime
+ updated_at: Optional[datetime]
+
+
class DeviceNetworkToken(TypedDict):
token: uuid.UUID
network: GenericID
name: str
- crated_at: datetime
+ created_at: datetime
+
+
+class NetworkQuery(TypedDict, total=False):
+ page: int
+ amount: int
+ fields: list[str]
+ filter: dict
+ orderBy: list[str]
+
+
+class ListTokenQuery(TypedDict, total=False):
+ page: int
+ amount: int
+ fields: list[str]
+ filter: dict
+ orderBy: list[str]
diff --git a/src/tagoio_sdk/modules/Resources/Profile.py b/src/tagoio_sdk/modules/Resources/Profile.py
index ca9fdf2..9f8f803 100644
--- a/src/tagoio_sdk/modules/Resources/Profile.py
+++ b/src/tagoio_sdk/modules/Resources/Profile.py
@@ -1,28 +1,46 @@
+from typing import Dict
from typing import List
from typing import Optional
from tagoio_sdk.common.Common_Type import GenericID
+from tagoio_sdk.common.Common_Type import GenericToken
from tagoio_sdk.common.Common_Type import Query
+from tagoio_sdk.common.Common_Type import TokenCreateResponse
+from tagoio_sdk.common.Common_Type import TokenData
from tagoio_sdk.common.Common_Type import TokenDataList
from tagoio_sdk.common.tagoio_module import TagoIOModule
+from tagoio_sdk.modules.Resources.Profile_Type import AuditLog
+from tagoio_sdk.modules.Resources.Profile_Type import AuditLogFilter
+from tagoio_sdk.modules.Resources.Profile_Type import ProfileCreateInfo
+from tagoio_sdk.modules.Resources.Profile_Type import ProfileCredentials
from tagoio_sdk.modules.Resources.Profile_Type import ProfileInfo
from tagoio_sdk.modules.Resources.Profile_Type import ProfileListInfo
from tagoio_sdk.modules.Resources.Profile_Type import ProfileSummary
+from tagoio_sdk.modules.Resources.Profile_Type import ProfileTeam
+from tagoio_sdk.modules.Resources.Profile_Type import StatisticsDate
+from tagoio_sdk.modules.Resources.Profile_Type import UsageStatistic
from tagoio_sdk.modules.Utils.dateParser import dateParser
from tagoio_sdk.modules.Utils.dateParser import dateParserList
class Profile(TagoIOModule):
- """
- Manage profiles in account be sure to use an
- account token with “write” permissions when
- using functions like create, edit and delete.
- """
-
def info(self, profileID: GenericID) -> ProfileInfo:
"""
- Get Profile info
- :param: profileID Profile identification
+ @description:
+ Retrieves detailed information about a specific profile using its ID or 'current' for the active profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/198-profiles Profiles
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Account** / **Access profile** in Access Management.
+ ```python
+ resources = Resources()
+ profile_info = resources.profile.info("profile-id-123")
+ # Or get current profile
+ current_profile = resources.profile.info("current")
+ print(profile_info) # {'info': {'id': 'profile-id-123', 'account': 'account-id-123', ...}, ...}
+ ```
"""
result = self.doRequest(
{
@@ -37,7 +55,19 @@ def info(self, profileID: GenericID) -> ProfileInfo:
def list(self) -> list[ProfileListInfo]:
"""
- Lists all the profiles in your account
+ @description:
+ Retrieves a list of all profiles associated with the current account.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/198-profiles Profiles
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Account** / **Access profile** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.profile.list()
+ print(result) # [{'id': 'profile-id-123', 'name': 'Profile Test', ...}]
+ ```
"""
result = self.doRequest(
{
@@ -49,8 +79,19 @@ def list(self) -> list[ProfileListInfo]:
def summary(self, profileID: GenericID) -> ProfileSummary:
"""
- Gets profile summary
- :param: profileID Profile identification
+ @description:
+ Retrieves a summary of the profile's usage and statistics.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/198-profiles Profiles
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Account** / **Access profile** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.profile.summary("profile-id-123")
+ print(result) # {'amount': {'device': 10, 'bucket': 10, 'dashboard': 5, ...}, ...}
+ ```
"""
result = self.doRequest(
{
@@ -60,12 +101,24 @@ def summary(self, profileID: GenericID) -> ProfileSummary:
)
return result
- def tokenList(
- self, profileID: GenericID, queryObj: Optional[Query] = None
- ) -> List[TokenDataList]:
+ def tokenList(self, profileID: GenericID, queryObj: Optional[Query] = None) -> List[TokenDataList]:
"""
- Lists all the tokens in your account
- :param: profileID Profile identification
+ @description:
+ Retrieves a list of all tokens associated with a specific profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/495-account-token Account Token
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.tokenList("profile-id-123", {
+ "page": 1,
+ "amount": 20,
+ "fields": ["name", "token", "permission"]
+ })
+ print(result) # [{'name': 'Token #1', 'token': 'token-value', 'permission': 'full', ...}, ...]
+ ```
"""
if queryObj is None:
@@ -91,8 +144,315 @@ def tokenList(
}
)
- result = dateParserList(
- result, ["last_authorization", "expire_time", "created_at"]
+ result = dateParserList(result, ["last_authorization", "expire_time", "created_at"])
+
+ return result
+
+ def create(self, profileObj: ProfileCreateInfo, allocate_free_resources: bool = False) -> Dict[str, GenericID]:
+ """
+ @description:
+ Creates a new profile with the specified name and optional resource allocation settings.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/198-profiles Profiles
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.create({"name": "New Profile"}, allocate_free_resources=True)
+ print(result) # {'id': 'profile-id-123'}
+ ```
+ """
+ params = {}
+ if allocate_free_resources:
+ params["allocate_free_resources"] = allocate_free_resources
+
+ result = self.doRequest({"path": "/profile/", "method": "POST", "body": profileObj, "params": params})
+
+ return result
+
+ def edit(self, profileID: GenericID, profileObj: Dict) -> str:
+ """
+ @description:
+ Updates profile information with the provided data.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/198-profiles Profiles
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.edit("profile-id-123", {"name": "Updated Profile Name"})
+ print(result) # Successfully Updated
+ ```
+ """
+ result = self.doRequest({"path": f"/profile/{profileID}", "method": "PUT", "body": profileObj})
+
+ return result
+
+ def delete(self, profileID: GenericID, credentials: ProfileCredentials) -> str:
+ """
+ @description:
+ Permanently removes a profile from the account.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/526-two-factor-authentication Two-Factor Authentication (2FA)
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ # The "pin_code" field is required when 2FA is activated
+ result = resources.profile.delete("profile-id-123", {"password": "your-password", "pin_code": "123456"})
+ print(result) # Successfully Removed
+ ```
+ """
+ result = self.doRequest({"path": f"/profile/{profileID}", "method": "DELETE", "body": credentials})
+
+ return result
+
+ def usageStatisticList(
+ self, profileID: GenericID, dateObj: Optional[StatisticsDate] = None
+ ) -> List[UsageStatistic]:
+ """
+ @description:
+ Retrieves usage statistics for a profile within a specified time period.
+ Usage statistics are cumulative: if a service was not used in a time period,
+ the statistics for that time period will not be in the object.
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Account** / **Access profile statistics** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.profile.usageStatisticList("profile-id-123", {
+ "start_date": "2024-09-01",
+ "end_date": "2024-12-31",
+ "periodicity": "day"
+ })
+ print(result) # [{'time': '2024-09-02T00:01:29.749Z', 'analysis': 0.07, 'data_records': 67254, ...}, ...]
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/profile/{profileID}/statistics",
+ "method": "GET",
+ "params": dateObj or {},
+ }
)
+ result = dateParserList(result, ["time"])
+
+ return result
+
+ def auditLog(self, profileID: GenericID, filterObj: Optional[AuditLogFilter] = None) -> AuditLog:
+ """
+ @description:
+ Creates a new audit log query for tracking profile activities.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/audit-log Audit Log
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.auditLog("profile-id-123", {
+ "start_date": "2024-12-01",
+ "end_date": "2024-12-07"
+ })
+ print(result)
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/profile/{profileID}/auditlog",
+ "method": "GET",
+ "params": filterObj or {},
+ }
+ )
+
+ if result.get("events"):
+ result["events"] = dateParserList(result["events"], ["date"])
+
+ return result
+
+ def auditLogQuery(self, profileID: GenericID, queryId: str) -> AuditLog:
+ """
+ @description:
+ Retrieves audit log entries using a previously created query.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/audit-log Audit Log
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.auditLogQuery("profile-id-123", "query-id-456")
+ print(result)
+ ```
+ """
+ result = self.doRequest({"path": f"/profile/{profileID}/auditlog/{queryId}", "method": "GET"})
+
+ if result.get("events"):
+ result["events"] = dateParserList(result["events"], ["date"])
+
+ return result
+
+ def serviceEdit(self, profileID: GenericID, serviceObj: Dict) -> str:
+ """
+ @description:
+ Updates service configuration and resource limits for a profile.
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.serviceEdit("profile-id-123", {
+ "input": 350000,
+ "output": 342153,
+ "analysis": 5
+ })
+ print(result) # Profile resource allocation Successfully Updated
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/profile/{profileID}/services",
+ "method": "POST",
+ "body": serviceObj,
+ }
+ )
+
+ return result
+
+ def transferTokenToAnotherProfile(self, targetProfileID: GenericID) -> str:
+ """
+ @description:
+ Transfers the current authentication token to another profile.
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.transferTokenToAnotherProfile("target-profile-123")
+ print(result)
+ ```
+ """
+ result = self.doRequest({"path": f"/profile/switch/{targetProfileID}", "method": "PUT"})
+
+ return result
+
+ def tokenCreate(self, profileID: GenericID, tokenParams: TokenData) -> TokenCreateResponse:
+ """
+ @description:
+ Creates a new authentication token for the specified profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/495-account-token Account Token
+ https://help.tago.io/portal/en/kb/articles/526-two-factor-authentication Two-Factor Authentication (2FA)
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ # The "pin_code" / "otp_type" field is required when 2FA is activated
+ result = resources.profile.tokenCreate("profile-id-123", {
+ "name": "API Access",
+ "permission": "full",
+ "email": "example@email.com",
+ "password": "your-password"
+ })
+ print(result) # {'token': 'token-value', 'name': 'API Access', ...}
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/profile/{profileID}/token",
+ "method": "POST",
+ "body": tokenParams,
+ }
+ )
+
+ result = dateParser(result, ["expire_date"])
+
+ return result
+
+ def tokenDelete(self, profileID: GenericID, token: GenericToken) -> str:
+ """
+ @description:
+ Revokes and removes an authentication token from the profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/495-account-token Account Token
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.tokenDelete("profile-id-123", "token-xyz")
+ print(result) # Token Successfully Removed
+ ```
+ """
+ result = self.doRequest({"path": f"/profile/{profileID}/token/{token}", "method": "DELETE"})
+
+ return result
+
+ def addTeamMember(self, profileID: GenericID, email: str) -> str:
+ """
+ @description:
+ Adds a new team member to the profile using their email address.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/106-sharing-your-profile Team Management - Sharing your Profile
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.addTeamMember("profile-id-123", "user@example.com")
+ print(result) # User invited
+ ```
+ """
+ result = self.doRequest(
+ {
+ "path": f"/profile/{profileID}/team",
+ "method": "POST",
+ "body": {"email": email},
+ }
+ )
+
+ return result
+
+ def teamList(self, profileID: GenericID) -> List[ProfileTeam]:
+ """
+ @description:
+ Retrieves a list of all team members that have access to the specified profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/106-sharing-your-profile Team Management - Sharing your Profile
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.profile.teamList("profile-id-123")
+ print(result) # [{'id': 'account-id-123', 'active': False, 'name': 'John Doe', ...}, ...]
+ ```
+ """
+ result = self.doRequest({"path": f"/profile/{profileID}/team", "method": "GET"})
+
+ result = dateParserList(result, ["created_at"])
+
+ return result
+
+ def deleteTeamMember(self, profileID: GenericID, accountId: str) -> str:
+ """
+ @description:
+ Removes a team member from the profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/106-sharing-your-profile Team Management - Sharing your Profile
+
+ @example:
+ If receive an error "Authorization Denied", check policy in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.profile.deleteTeamMember("profile-id-123", "account-id-456")
+ print(result) # Account Successfully Removed
+ ```
+ """
+ result = self.doRequest({"path": f"/profile/{profileID}/team/{accountId}", "method": "DELETE"})
+
return result
diff --git a/src/tagoio_sdk/modules/Resources/Profile_Type.py b/src/tagoio_sdk/modules/Resources/Profile_Type.py
index 2367372..fcf0acf 100644
--- a/src/tagoio_sdk/modules/Resources/Profile_Type.py
+++ b/src/tagoio_sdk/modules/Resources/Profile_Type.py
@@ -1,4 +1,6 @@
from datetime import datetime
+from typing import Literal
+from typing import Optional
from typing import TypedDict
from typing import Union
@@ -84,3 +86,101 @@ class ProfileSummary(TypedDict):
amount: amount
limit_used: limit_used
addons: ProfileAddOns
+
+
+class UsageStatistic(TypedDict, total=False):
+ """
+ Type for a single usage statistic with timestamp.
+
+ Not all of the services will be present for every statistic,
+ only if for the usage period the service was used.
+ """
+
+ time: datetime
+ input: Union[int, float]
+ output: Union[int, float]
+ analysis: Union[int, float]
+ sms: Union[int, float]
+ email: Union[int, float]
+ data_records: Union[int, float]
+ run_users: Union[int, float]
+ push_notification: Union[int, float]
+ file_storage: Union[int, float]
+ tcore: Union[int, float]
+
+
+class AuditLogEvent(TypedDict):
+ resourceName: str
+ message: str
+ resourceID: GenericID
+ who: GenericID
+ date: datetime
+
+
+class AuditLogStatistics(TypedDict):
+ recordsMatched: int
+ recordsScanned: int
+ bytesScanned: int
+
+
+class AuditLog(TypedDict, total=False):
+ events: list[AuditLogEvent]
+ statistics: AuditLogStatistics
+ status: Literal["Running", "Complete", "Failed", "Timeout", "Unknown"]
+ queryId: str
+
+
+class AuditLogFilter(TypedDict, total=False):
+ resourceID: GenericID
+ resourceName: Literal[
+ "action",
+ "am",
+ "analysis",
+ "connector",
+ "dashboard",
+ "device",
+ "dictionary",
+ "network",
+ "profile",
+ "run",
+ "runuser",
+ ]
+ find: str
+ start_date: Union[str, datetime]
+ end_date: Union[str, datetime]
+ limit: int
+
+
+class AddonInfo(TypedDict):
+ id: GenericID
+ name: str
+ logo_url: Optional[str]
+
+
+class StatisticsDate(TypedDict, total=False):
+ """
+ Parameters for fetching usage statistics.
+ """
+
+ timezone: str
+ date: Union[str, datetime]
+ start_date: Union[str, datetime]
+ end_date: Union[str, datetime]
+ periodicity: Literal["hour", "day", "month"]
+
+
+class ProfileTeam(TypedDict):
+ active: bool
+ created_at: datetime
+ email: str
+ id: str
+ name: str
+
+
+class ProfileCreateInfo(TypedDict):
+ name: str
+
+
+class ProfileCredentials(TypedDict, total=False):
+ password: str
+ pin_code: str
diff --git a/src/tagoio_sdk/modules/Resources/Run.py b/src/tagoio_sdk/modules/Resources/Run.py
index 63d7f8e..e7c4bf2 100644
--- a/src/tagoio_sdk/modules/Resources/Run.py
+++ b/src/tagoio_sdk/modules/Resources/Run.py
@@ -1,5 +1,5 @@
+from typing import Dict
from typing import Optional
-from typing import TypedDict
from tagoio_sdk.common.Common_Type import GenericID
from tagoio_sdk.common.Common_Type import Query
@@ -9,6 +9,7 @@
from tagoio_sdk.modules.Resources.Notification_Type import NotificationInfo
from tagoio_sdk.modules.Resources.Run_Type import CustomDomainCreate
from tagoio_sdk.modules.Resources.Run_Type import CustomDomainInfo
+from tagoio_sdk.modules.Resources.Run_Type import EmailTestData
from tagoio_sdk.modules.Resources.Run_Type import LoginAsUserOptions
from tagoio_sdk.modules.Resources.Run_Type import LoginResponse
from tagoio_sdk.modules.Resources.Run_Type import RunInfo
@@ -21,13 +22,23 @@
class Run(TagoIOModule):
- """
- Manage services in account
- Be sure to use an account token with “write” permissions when using
- functions like create, edit and delete.
- """
-
def info(self) -> RunInfo:
+ """
+ @description:
+ Retrieves information about the current Run environment configuration.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun
+ https://help.tago.io/portal/en/kb/articles/run-themes Run Themes
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Profile** / **Access TagoRun settings** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.info()
+ print(result) # {'name': 'My Run Environment', 'logo': 'https://example.com/logo.png', ...}
+ ```
+ """
result = self.doRequest(
{
"path": "/run",
@@ -37,7 +48,23 @@ def info(self) -> RunInfo:
return result
- def edit(self, data: RunInfo) -> str:
+ def edit(self, data: Dict) -> str:
+ """
+ @description:
+ Updates the Run environment configuration settings.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun
+ https://help.tago.io/portal/en/kb/articles/run-themes Run Themes
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Profile** / **Edit TagoRun settings** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.edit({"name": "My Run Environment", "logo": "https://example.com/logo.png"})
+ print(result) # TagoIO Run Successfully Updated
+ ```
+ """
result = self.doRequest(
{
"path": "/run",
@@ -48,7 +75,28 @@ def edit(self, data: RunInfo) -> str:
return result
- def listUsers(self, query: Query) -> list[UserInfo]:
+ def listUsers(self, query: Optional[Query] = None) -> list[UserInfo]:
+ """
+ @description:
+ Retrieves a paginated list of Run users with customizable fields and filtering options.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun
+
+ @example:
+ If receive an error "Authorization Denied", or return empty list check policy **Run User** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.listUsers({
+ "page": 1,
+ "fields": ["id", "name", "email"],
+ "amount": 20
+ })
+ print(result) # [{'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com'}]
+ ```
+ """
+ if query is None:
+ query = {}
if "orderBy" in query:
firstArgument = query["orderBy"][0]
secondArgument = query["orderBy"][1]
@@ -74,6 +122,21 @@ def listUsers(self, query: Query) -> list[UserInfo]:
return result
def userInfo(self, userID: GenericID) -> UserInfo:
+ """
+ @description:
+ Retrieves detailed information about a specific Run user.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Access** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.userInfo("user-id-123")
+ print(result) # {'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com', ...}
+ ```
+ """
result = self.doRequest(
{
"path": f"/run/users/{userID}",
@@ -85,7 +148,27 @@ def userInfo(self, userID: GenericID) -> UserInfo:
return result
- def userCreate(self, data: UserCreateInfo) -> str:
+ def userCreate(self, data: UserCreateInfo) -> Dict[str, str]:
+ """
+ @description:
+ Creates a new user in the Run environment.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Create** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.userCreate({
+ "name": "John Doe",
+ "email": "john@example.com",
+ "password": "secure123",
+ "timezone": "America/New_York"
+ })
+ print(result) # {'user': 'user-id-123'}
+ ```
+ """
result = self.doRequest(
{
"path": "/run/users",
@@ -96,7 +179,22 @@ def userCreate(self, data: UserCreateInfo) -> str:
return result
- def userEdit(self, userID: GenericID, data: UserInfo) -> str:
+ def userEdit(self, userID: GenericID, data: Dict) -> str:
+ """
+ @description:
+ Updates information for an existing Run user.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Edit** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.userEdit("user-id-123", {"name": "Updated Name"})
+ print(result) # TagoIO Run User Successfully Updated
+ ```
+ """
result = self.doRequest(
{
"path": f"/run/users/{userID}",
@@ -108,6 +206,21 @@ def userEdit(self, userID: GenericID, data: UserInfo) -> str:
return result
def userDelete(self, userID: GenericID) -> str:
+ """
+ @description:
+ Permanently deletes a user from the Run environment.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Delete** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.userDelete("user-id-123")
+ print(result) # Successfully Removed
+ ```
+ """
result = self.doRequest(
{
"path": f"/run/users/{userID}",
@@ -117,9 +230,19 @@ def userDelete(self, userID: GenericID) -> str:
return result
- def loginAsUser(
- self, userID: GenericID, options: Optional[LoginAsUserOptions]
- ) -> LoginResponse:
+ def loginAsUser(self, userID: GenericID, options: Optional[LoginAsUserOptions] = None) -> LoginResponse:
+ """
+ @description:
+ Generates a login token to authenticate as a specific Run user.
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Login as user** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.loginAsUser("user-id-123")
+ print(result["token"]) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
+ ```
+ """
result = self.doRequest(
{
"path": f"/run/users/{userID}/login",
@@ -132,11 +255,18 @@ def loginAsUser(
return result
- class emailData(TypedDict):
- subject: str
- body: str
-
- def emailTest(self, data: emailData) -> str:
+ def emailTest(self, data: EmailTestData) -> str:
+ """
+ @description:
+ Tests the email configuration by sending a test message.
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.emailTest({"subject": "Test Email", "body": "This is a test message"})
+ print(result) # E-mail sent to example@email.com
+ ```
+ """
result = self.doRequest(
{
"path": "/run/email_test",
@@ -148,6 +278,21 @@ def emailTest(self, data: emailData) -> str:
return result
def notificationList(self, userID: GenericID) -> list[NotificationInfo]:
+ """
+ @description:
+ Retrieves a list of notifications for a specific Run user.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Access notification** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.notificationList("user-id-123")
+ print(result) # [{'id': 'notification-id-123', 'title': 'System Update', 'message': 'Features', ...}]
+ ```
+ """
result = self.doRequest(
{
"path": f"/run/notification/{userID}",
@@ -157,9 +302,25 @@ def notificationList(self, userID: GenericID) -> list[NotificationInfo]:
return result
- def notificationCreate(
- self, userID: GenericID, data: NotificationCreate
- ) -> NotificationCreateReturn:
+ def notificationCreate(self, userID: GenericID, data: NotificationCreate) -> NotificationCreateReturn:
+ """
+ @description:
+ Creates a new notification for a Run user.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Create notification** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.notificationCreate("user-id-123", {
+ "title": "Update",
+ "message": "New feature available"
+ })
+ print(result) # {'id': 'notification-id-123'}
+ ```
+ """
result = self.doRequest(
{
"path": "/run/notification/",
@@ -173,9 +334,22 @@ def notificationCreate(
return result
- def notificationEdit(
- self, notificationID: GenericID, data: NotificationCreate
- ) -> str:
+ def notificationEdit(self, notificationID: GenericID, data: Dict) -> str:
+ """
+ @description:
+ Updates an existing notification in the Run environment.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Edit notification** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.notificationEdit("notification-id-123", {"title": "Updated Title"})
+ print(result) # TagoIO Notification User Successfully Updated
+ ```
+ """
result = self.doRequest(
{
"path": f"/run/notification/{notificationID}",
@@ -187,6 +361,21 @@ def notificationEdit(
return result
def notificationDelete(self, notificationID: GenericID) -> str:
+ """
+ @description:
+ Deletes a notification from the Run environment.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users
+
+ @example:
+ If receive an error "Authorization Denied", check policy **Run User** / **Delete notification** in Access Management.
+ ```python
+ resources = Resources()
+ result = resources.run.notificationDelete("notification-id-123")
+ print(result) # Successfully Removed
+ ```
+ """
result = self.doRequest(
{
"path": f"/run/notification/{notificationID}",
@@ -198,9 +387,19 @@ def notificationDelete(self, notificationID: GenericID) -> str:
def ssoSAMLInfo(self) -> RunSAMLInfo:
"""
- Get the SAML Single Sign-On information for the account's RUN.
+ @description:
+ Retrieves the SAML Single Sign-On configuration information for the Run environment.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/491-single-sign-on-sso Single Sign-On (SSO)
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.ssoSAMLInfo()
+ print(result) # {'sp': {'entity_id': 'https://example.com', ...}, ...}
+ ```
"""
-
result = self.doRequest(
{
"path": "/run/sso/saml",
@@ -212,10 +411,22 @@ def ssoSAMLInfo(self) -> RunSAMLInfo:
def ssoSAMLEdit(self, data: RunSAMLEditInfo) -> str:
"""
- Edit the SAML Single Sign-On metadata and mappings for the account's RUN.
- :param: data Updated data for a RUN's SAML Single Sign-On configuration.
+ @description:
+ Updates the SAML SSO configuration for the Run environment.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/491-single-sign-on-sso Single Sign-On (SSO)
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.ssoSAMLEdit({
+ "active": True,
+ "idp_metadata": "..."
+ })
+ print(result) # TagoIO Run SAML SSO Successfully Updated
+ ```
"""
-
result = self.doRequest(
{
"path": "/run/sso/saml",
@@ -226,16 +437,23 @@ def ssoSAMLEdit(self, data: RunSAMLEditInfo) -> str:
return result
- def createCustomDomain(
- self, profile_id: str, customDomainData: CustomDomainCreate
- ) -> str:
+ def createCustomDomain(self, profile_id: str, customDomainData: CustomDomainCreate) -> str:
"""
- Create a TagoRUN custom domain for the profile.
- :param: profile_id ID of the profile
- :param: customDomainData query params
- :returns: Success message.
+ @description:
+ Creates a custom domain configuration for the Run environment.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.createCustomDomain("profile-id-123", {
+ "domain": "app.mycompany.com"
+ })
+ print(result) # Custom domain created successfully
+ ```
"""
-
result = self.doRequest(
{
"path": f"/run/customdomain/{profile_id}",
@@ -248,11 +466,19 @@ def createCustomDomain(
def getCustomDomain(self, profile_id: str) -> CustomDomainInfo:
"""
- set details of TagoRun custom domain for the profile.
- :param: profile_id ID of the profile
- :returns: Data for the profile's custom DNS configuration.
+ @description:
+ Retrieves the custom domain configuration for a Run profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.getCustomDomain("profile-id-123")
+ print(result) # {'domain': 'app.mycompany.com', 'verified': True, ...}
+ ```
"""
-
result = self.doRequest(
{
"path": f"/run/customdomain/{profile_id}",
@@ -266,11 +492,19 @@ def getCustomDomain(self, profile_id: str) -> CustomDomainInfo:
def deleteCustomDomain(self, profile_id: str) -> str:
"""
- delete a TagoRUN custom domain for the profile.
- :param: profile_id ID of the profile
- :returns: Success message.
+ @description:
+ Removes the custom domain configuration from a Run profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.deleteCustomDomain("profile-id-123")
+ print(result) # Custom domain deleted successfully
+ ```
"""
-
result = self.doRequest(
{
"path": f"/run/customdomain/{profile_id}",
@@ -281,11 +515,19 @@ def deleteCustomDomain(self, profile_id: str) -> str:
def regenerateCustomDomain(self, profile_id: str) -> str:
"""
- Regenerate a TagoRUN custom domain for the profile.
- :param: profile_id ID of the profile
- :returns: Success message.
+ @description:
+ Regenerates the custom domain configuration for a Run profile.
+
+ @see:
+ https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration
+
+ @example:
+ ```python
+ resources = Resources({"token": "YOUR-PROFILE-TOKEN"})
+ result = resources.run.regenerateCustomDomain("profile-id-123")
+ print(result) # Custom domain regenerated successfully
+ ```
"""
-
result = self.doRequest(
{
"path": f"/run/customdomain/regenerate/{profile_id}",
diff --git a/src/tagoio_sdk/modules/Resources/Run_Type.py b/src/tagoio_sdk/modules/Resources/Run_Type.py
index e18dcb8..6e22b66 100644
--- a/src/tagoio_sdk/modules/Resources/Run_Type.py
+++ b/src/tagoio_sdk/modules/Resources/Run_Type.py
@@ -255,6 +255,17 @@ class LoginAsUserOptions(TypedDict):
"""
+class EmailTestData(TypedDict):
+ subject: str
+ """
+ Subject of the test email.
+ """
+ body: str
+ """
+ Body content of the test email.
+ """
+
+
class SAMLAttributeMappings(TypedDict):
email: str
firstName: str
diff --git a/tests/Resources/test_dashboards.py b/tests/Resources/test_dashboards.py
new file mode 100644
index 0000000..981782c
--- /dev/null
+++ b/tests/Resources/test_dashboards.py
@@ -0,0 +1,564 @@
+import os
+
+from requests_mock.mocker import Mocker
+
+from tagoio_sdk.modules.Resources.Dashboards_Type import DashboardInfo
+from tagoio_sdk.modules.Resources.Resources import Resources
+
+os.environ["T_ANALYSIS_TOKEN"] = "your_token_value"
+
+
+def mockDashboardList() -> list[DashboardInfo]:
+ return {
+ "status": True,
+ "result": [
+ {
+ "id": "dashboard_id_1",
+ "label": "Dashboard 1",
+ "created_at": "2023-02-21T15:17:35.759Z",
+ "updated_at": "2023-02-21T15:17:35.759Z",
+ "last_access": "2023-02-21T15:17:35.759Z",
+ "arrangement": [],
+ "tags": [{"key": "type", "value": "monitoring"}],
+ "visible": True,
+ },
+ {
+ "id": "dashboard_id_2",
+ "label": "Dashboard 2",
+ "created_at": "2023-02-21T16:17:35.759Z",
+ "updated_at": "2023-02-21T16:17:35.759Z",
+ "last_access": "2023-02-21T16:17:35.759Z",
+ "arrangement": [],
+ "tags": [{"key": "type", "value": "analytics"}],
+ "visible": True,
+ },
+ ],
+ }
+
+
+def mockDashboardInfo() -> DashboardInfo:
+ return {
+ "status": True,
+ "result": {
+ "id": "dashboard_id_1",
+ "label": "Dashboard 1",
+ "created_at": "2023-02-21T15:17:35.759Z",
+ "updated_at": "2023-02-21T15:17:35.759Z",
+ "last_access": "2023-02-21T15:17:35.759Z",
+ "arrangement": [],
+ "tags": [{"key": "type", "value": "monitoring"}],
+ "visible": True,
+ "group_by": [],
+ "tabs": [],
+ "icon": {"url": "https://example.com/icon.png", "color": "#ff0000"},
+ "background": {},
+ "type": "normal",
+ "blueprint_device_behavior": "more_than_one",
+ "blueprint_selector_behavior": "open",
+ "theme": {},
+ "setup": {},
+ },
+ }
+
+
+def mockCreateDashboard() -> dict:
+ return {
+ "status": True,
+ "result": {"dashboard": "dashboard_id_new"},
+ }
+
+
+def mockDuplicateDashboard() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "dashboard_id": "dashboard_id_duplicate",
+ "message": "Dashboard duplicated successfully",
+ },
+ }
+
+
+def mockPublicKey() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "token": "public_token_123",
+ "expire_time": "2025-01-02T00:00:00.000Z",
+ },
+ }
+
+
+def mockDevicesRelated() -> list:
+ return {
+ "status": True,
+ "result": [
+ {"id": "device_id_1", "bucket": "bucket_id_1"},
+ {"id": "device_id_2", "bucket": "bucket_id_2"},
+ ],
+ }
+
+
+def mockAnalysisRelated() -> list:
+ return {
+ "status": True,
+ "result": [
+ {"id": "analysis_id_1", "name": "Analysis 1"},
+ {"id": "analysis_id_2", "name": "Analysis 2"},
+ ],
+ }
+
+
+def testDashboardsMethodList(requests_mock: Mocker) -> None:
+ """Test listDashboard method of Dashboards class."""
+ mock_response = mockDashboardList()
+ requests_mock.get("https://api.tago.io/dashboard", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ query = {
+ "page": 1,
+ "fields": ["id", "label"],
+ "amount": 20,
+ "orderBy": ["label", "asc"],
+ }
+
+ result = resources.dashboards.listDashboard(query)
+
+ # Check if the result is a list
+ assert isinstance(result, list)
+ # Check if the result has the expected items
+ assert len(result) == 2
+ # Check if items have expected properties
+ assert result[0]["id"] == "dashboard_id_1"
+ assert result[0]["label"] == "Dashboard 1"
+ assert result[1]["id"] == "dashboard_id_2"
+ assert result[1]["label"] == "Dashboard 2"
+
+
+def testDashboardsMethodCreate(requests_mock: Mocker) -> None:
+ """Test create method of Dashboards class."""
+ mock_response = mockCreateDashboard()
+ requests_mock.post("https://api.tago.io/dashboard", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ dashboard_data = {
+ "label": "New Dashboard",
+ "arrangement": [],
+ "tags": [{"key": "type", "value": "monitoring"}],
+ "visible": True,
+ }
+
+ result = resources.dashboards.create(dashboard_data)
+
+ # Check if result has expected structure
+ assert result["dashboard"] == "dashboard_id_new"
+
+
+def testDashboardsMethodEdit(requests_mock: Mocker) -> None:
+ """Test edit method of Dashboards class."""
+ mock_response = {
+ "status": True,
+ "result": "Successfully Updated",
+ }
+
+ requests_mock.put("https://api.tago.io/dashboard/dashboard_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ dashboard_data = {
+ "label": "Updated Dashboard",
+ "visible": False,
+ }
+
+ result = resources.dashboards.edit("dashboard_id_1", dashboard_data)
+
+ # Check if result has expected message
+ assert result == "Successfully Updated"
+
+
+def testDashboardsMethodDelete(requests_mock: Mocker) -> None:
+ """Test delete method of Dashboards class."""
+ mock_response = {
+ "status": True,
+ "result": "Successfully Removed",
+ }
+
+ requests_mock.delete("https://api.tago.io/dashboard/dashboard_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.delete("dashboard_id_1")
+
+ # Check if result has expected message
+ assert result == "Successfully Removed"
+
+
+def testDashboardsMethodInfo(requests_mock: Mocker) -> None:
+ """Test info method of Dashboards class."""
+ mock_response = mockDashboardInfo()
+ requests_mock.get("https://api.tago.io/dashboard/dashboard_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.info("dashboard_id_1")
+
+ # Check if result has expected properties
+ assert result["id"] == "dashboard_id_1"
+ assert result["label"] == "Dashboard 1"
+ assert result["visible"] == True
+ assert result["type"] == "normal"
+ assert len(result["tags"]) == 1
+ assert result["tags"][0]["key"] == "type"
+ assert result["tags"][0]["value"] == "monitoring"
+
+
+def testDashboardsMethodDuplicate(requests_mock: Mocker) -> None:
+ """Test duplicate method of Dashboards class."""
+ mock_response = mockDuplicateDashboard()
+ requests_mock.post("https://api.tago.io/dashboard/dashboard_id_1/duplicate", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ duplicate_options = {"new_label": "Copy of Dashboard 1"}
+
+ result = resources.dashboards.duplicate("dashboard_id_1", duplicate_options)
+
+ # Check if result has expected properties
+ assert result["dashboard_id"] == "dashboard_id_duplicate"
+ assert result["message"] == "Dashboard duplicated successfully"
+
+
+def testDashboardsMethodGetPublicKey(requests_mock: Mocker) -> None:
+ """Test getPublicKey method of Dashboards class."""
+ mock_response = mockPublicKey()
+ requests_mock.get("https://api.tago.io/dashboard/dashboard_id_1/share/public", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.getPublicKey("dashboard_id_1", "1day")
+
+ # Check if result has expected properties
+ assert result["token"] == "public_token_123"
+ assert "expire_time" in result
+
+
+def testDashboardsMethodListDevicesRelated(requests_mock: Mocker) -> None:
+ """Test listDevicesRelated method of Dashboards class."""
+ mock_response = mockDevicesRelated()
+ requests_mock.get("https://api.tago.io/dashboard/dashboard_id_1/devices", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.listDevicesRelated("dashboard_id_1")
+
+ # Check if the result is a list
+ assert isinstance(result, list)
+ # Check if the result has the expected items
+ assert len(result) == 2
+ # Check if items have expected properties
+ assert result[0]["id"] == "device_id_1"
+ assert result[0]["bucket"] == "bucket_id_1"
+
+
+def testDashboardsMethodListAnalysisRelated(requests_mock: Mocker) -> None:
+ """Test listAnalysisRelated method of Dashboards class."""
+ mock_response = mockAnalysisRelated()
+ requests_mock.get("https://api.tago.io/dashboard/dashboard_id_1/analysis", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.listAnalysisRelated("dashboard_id_1")
+
+ # Check if the result is a list
+ assert isinstance(result, list)
+ # Check if the result has the expected items
+ assert len(result) == 2
+ # Check if items have expected properties
+ assert result[0]["id"] == "analysis_id_1"
+ assert result[0]["name"] == "Analysis 1"
+
+
+def testDashboardsMethodRunWidgetHeaderButtonAnalysis(requests_mock: Mocker) -> None:
+ """Test runWidgetHeaderButtonAnalysis method of Dashboards class."""
+ mock_response = {
+ "status": True,
+ "result": "Analysis executed successfully",
+ }
+
+ requests_mock.post(
+ "https://api.tago.io/analysis/analysis_id_1/run/dashboard_id_1/widget_id_1",
+ json=mock_response,
+ )
+
+ resources = Resources({"token": "your_token_value"})
+
+ scope_data = {"custom_data": "value"}
+
+ result = resources.dashboards.runWidgetHeaderButtonAnalysis(
+ "analysis_id_1", "dashboard_id_1", "widget_id_1", scope_data
+ )
+
+ # Check if result has expected message
+ assert result == "Analysis executed successfully"
+
+
+# Widget tests
+
+
+def mockWidgetInfo() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "id": "widget_id_1",
+ "label": "Temperature Widget",
+ "type": "display",
+ "data": [
+ {
+ "origin": "device_id_1",
+ "query": "last_value",
+ "variables": ["temperature"],
+ }
+ ],
+ "display": {
+ "show_units": True,
+ "show_variables": True,
+ "variables": [{"origin": "device_id_1", "variable": "temperature"}],
+ },
+ "dashboard": "dashboard_id_1",
+ "realtime": True,
+ "analysis_run": None,
+ },
+ }
+
+
+def mockCreateWidget() -> dict:
+ return {
+ "status": True,
+ "result": {"widget": "widget_id_new"},
+ }
+
+
+def testWidgetsMethodCreate(requests_mock: Mocker) -> None:
+ """Test create method of DashboardWidgets class."""
+ mock_response = mockCreateWidget()
+ requests_mock.post("https://api.tago.io/dashboard/dashboard_id_1/widget/", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ widget_data = {
+ "label": "New Widget",
+ "type": "display",
+ "data": [
+ {
+ "origin": "device_id_1",
+ "query": "last_value",
+ "variables": ["temperature"],
+ }
+ ],
+ "display": {
+ "show_units": True,
+ "show_variables": True,
+ },
+ }
+
+ result = resources.dashboards.widgets.create("dashboard_id_1", widget_data)
+
+ # Check if result has expected structure
+ assert result["widget"] == "widget_id_new"
+
+
+def testWidgetsMethodEdit(requests_mock: Mocker) -> None:
+ """Test edit method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": "Successfully Updated",
+ }
+
+ requests_mock.put(
+ "https://api.tago.io/dashboard/dashboard_id_1/widget/widget_id_1",
+ json=mock_response,
+ )
+
+ resources = Resources({"token": "your_token_value"})
+
+ widget_data = {"label": "Updated Widget"}
+
+ result = resources.dashboards.widgets.edit("dashboard_id_1", "widget_id_1", widget_data)
+
+ # Check if result has expected message
+ assert result == "Successfully Updated"
+
+
+def testWidgetsMethodDelete(requests_mock: Mocker) -> None:
+ """Test delete method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": "Successfully Removed",
+ }
+
+ requests_mock.delete(
+ "https://api.tago.io/dashboard/dashboard_id_1/widget/widget_id_1",
+ json=mock_response,
+ )
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.widgets.delete("dashboard_id_1", "widget_id_1")
+
+ # Check if result has expected message
+ assert result == "Successfully Removed"
+
+
+def testWidgetsMethodInfo(requests_mock: Mocker) -> None:
+ """Test info method of DashboardWidgets class."""
+ mock_response = mockWidgetInfo()
+ requests_mock.get(
+ "https://api.tago.io/dashboard/dashboard_id_1/widget/widget_id_1",
+ json=mock_response,
+ )
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.widgets.info("dashboard_id_1", "widget_id_1")
+
+ # Check if result has expected properties
+ assert result["id"] == "widget_id_1"
+ assert result["label"] == "Temperature Widget"
+ assert result["type"] == "display"
+ assert result["realtime"] == True
+ assert len(result["data"]) == 1
+
+
+def testWidgetsMethodGetData(requests_mock: Mocker) -> None:
+ """Test getData method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": {
+ "widget": {"id": "widget_id_1", "dashboard": "dashboard_id_1"},
+ "data": [{"variable": "temperature", "value": 25.5}],
+ },
+ }
+
+ requests_mock.get("https://api.tago.io/data/dashboard_id_1/widget_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ params = {"start_date": "2025-01-01", "end_date": "2025-12-31", "timezone": "UTC"}
+
+ result = resources.dashboards.widgets.getData("dashboard_id_1", "widget_id_1", params)
+
+ # Check if result has expected structure
+ assert "widget" in result
+ assert result["widget"]["id"] == "widget_id_1"
+
+
+def testWidgetsMethodSendData(requests_mock: Mocker) -> None:
+ """Test sendData method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": ["1 Data Added"],
+ }
+
+ requests_mock.post("https://api.tago.io/data/dashboard_id_1/widget_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ data = {
+ "origin": "device_id_1",
+ "variable": "temperature",
+ "value": 25.5,
+ "unit": "C",
+ }
+
+ result = resources.dashboards.widgets.sendData("dashboard_id_1", "widget_id_1", data)
+
+ # Check if result has expected message
+ assert isinstance(result, list)
+ assert result[0] == "1 Data Added"
+
+
+def testWidgetsMethodEditData(requests_mock: Mocker) -> None:
+ """Test editData method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": "Device Data Updated",
+ }
+
+ requests_mock.put("https://api.tago.io/data/dashboard_id_1/widget_id_1/data", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ data = {"origin": "device_id_1", "id": "data_id_1", "value": 26.0}
+
+ result = resources.dashboards.widgets.editData("dashboard_id_1", "widget_id_1", data)
+
+ # Check if result has expected message
+ assert result == "Device Data Updated"
+
+
+def testWidgetsMethodDeleteData(requests_mock: Mocker) -> None:
+ """Test deleteData method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": "Successfully Removed",
+ }
+
+ requests_mock.delete("https://api.tago.io/data/dashboard_id_1/widget_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+
+ id_pairs = ["data_1:device_1", "data_2:device_1"]
+
+ result = resources.dashboards.widgets.deleteData("dashboard_id_1", "widget_id_1", id_pairs)
+
+ # Check if result has expected message
+ assert result == "Successfully Removed"
+
+
+def testWidgetsMethodEditResource(requests_mock: Mocker) -> None:
+ """Test editResource method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": "Resource Updated",
+ }
+
+ requests_mock.put(
+ "https://api.tago.io/data/dashboard_id_1/widget_id_1/resource",
+ json=mock_response,
+ )
+
+ resources = Resources({"token": "your_token_value"})
+
+ resource_data = {
+ "device": "device_id_1",
+ "name": "Updated Device Name",
+ "active": True,
+ }
+
+ options = {"identifier": "my-identifier"}
+
+ result = resources.dashboards.widgets.editResource("dashboard_id_1", "widget_id_1", resource_data, options)
+
+ # Check if result has expected message
+ assert result == "Resource Updated"
+
+
+def testWidgetsMethodTokenGenerate(requests_mock: Mocker) -> None:
+ """Test tokenGenerate method of DashboardWidgets class."""
+ mock_response = {
+ "status": True,
+ "result": {"widget_token": "widget_token_123"},
+ }
+
+ requests_mock.get(
+ "https://api.tago.io/dashboard/dashboard_id_1/widget/widget_id_1/token",
+ json=mock_response,
+ )
+
+ resources = Resources({"token": "your_token_value"})
+
+ result = resources.dashboards.widgets.tokenGenerate("dashboard_id_1", "widget_id_1")
+
+ # Check if result has expected properties
+ assert result["widget_token"] == "widget_token_123"
diff --git a/tests/Resources/test_devices.py b/tests/Resources/test_devices.py
index 5969776..e700c74 100644
--- a/tests/Resources/test_devices.py
+++ b/tests/Resources/test_devices.py
@@ -1,4 +1,8 @@
import os
+
+from typing import Any
+from typing import Dict
+
from requests_mock.mocker import Mocker
from tagoio_sdk.modules.Resources.Resources import Resources
@@ -7,17 +11,139 @@
os.environ["T_ANALYSIS_TOKEN"] = "your_token_value"
+# Mock data generators
+def mockDeviceList() -> Dict[str, Any]:
+ """Generate mock device list response."""
+ return {
+ "status": True,
+ "result": [
+ {
+ "id": "device-id-123",
+ "name": "Temperature Sensor",
+ "active": True,
+ "type": "mutable",
+ "last_input": "2025-01-09T10:00:00.000Z",
+ "created_at": "2025-01-01T00:00:00.000Z",
+ }
+ ],
+ }
+
+
+def mockDeviceCreate() -> Dict[str, Any]:
+ """Generate mock device create response."""
+ return {
+ "status": True,
+ "result": {
+ "device_id": "device-id-new",
+ "bucket_id": "bucket-id-new",
+ "token": "new-token-123",
+ },
+ }
+
+
+def mockDeviceInfo() -> Dict[str, Any]:
+ """Generate mock device info response."""
+ return {
+ "status": True,
+ "result": {
+ "id": "device-id-123",
+ "name": "Temperature Sensor",
+ "active": True,
+ "type": "mutable",
+ "bucket": {"id": "bucket-id-123", "name": "Device Data"},
+ "network": "network-id-123",
+ "connector": "connector-id-123",
+ "last_input": "2025-01-09T10:00:00.000Z",
+ "created_at": "2025-01-01T00:00:00.000Z",
+ },
+ }
+
+
+def mockConfigParams() -> Dict[str, Any]:
+ """Generate mock configuration parameters."""
+ return {
+ "status": True,
+ "result": [
+ {"id": "param-id-123", "key": "threshold", "value": "25.5", "sent": False}
+ ],
+ }
+
+
+def mockTokenList() -> Dict[str, Any]:
+ """Generate mock token list response."""
+ return {
+ "status": True,
+ "result": [
+ {
+ "token": "token-123",
+ "name": "Default Token",
+ "permission": "full",
+ "device_id": "device-id-123",
+ "created_at": "2025-01-01T00:00:00.000Z",
+ }
+ ],
+ }
+
+
+def mockTokenCreate() -> Dict[str, Any]:
+ """Generate mock token create response."""
+ return {"status": True, "result": {"token": "new-token-456", "expire_date": None}}
+
+
+def mockDeviceData() -> Dict[str, Any]:
+ """Generate mock device data response."""
+ return {
+ "status": True,
+ "result": [
+ {
+ "id": "data-id-123",
+ "variable": "temperature",
+ "value": 25.5,
+ "unit": "°C",
+ "time": "2025-01-09T10:00:00.000Z",
+ }
+ ],
+ }
+
+
+def mockChunkList() -> Dict[str, Any]:
+ """Generate mock chunk list response."""
+ return {
+ "status": True,
+ "result": [
+ {
+ "id": "1704067200_1706745600",
+ "from_date": "2025-01-01T00:00:00.000Z",
+ "to_date": "2025-02-01T00:00:00.000Z",
+ "amount": 1000,
+ }
+ ],
+ }
+
+
+def mockBackupResponse() -> Dict[str, Any]:
+ """Generate mock backup response."""
+ return {
+ "status": True,
+ "result": {"file_address": "/backups/device-123/backup.csv"},
+ }
+
+
def testSendDeviceDataMethod(requests_mock: Mocker) -> None:
"""
:param requests_mock are a plugin of pytest to mock the requests.
"""
deviceID = "device1"
- requests_mock.post(f"https://api.tago.io/device/{deviceID}/data",
- json={"status": True, "result": "1 Data Added"})
+ requests_mock.post(
+ f"https://api.tago.io/device/{deviceID}/data",
+ json={"status": True, "result": "1 Data Added"},
+ )
resources = Resources()
- response = resources.devices.sendDeviceData(deviceID, {"variable": "test", "value": 1})
+ response = resources.devices.sendDeviceData(
+ deviceID, {"variable": "test", "value": 1}
+ )
assert response == "1 Data Added"
assert isinstance(response, str)
@@ -29,11 +155,15 @@ def testEditDeviceDataMethod(requests_mock: Mocker) -> None:
"""
deviceID = "device1"
- requests_mock.put(f"https://api.tago.io/device/{deviceID}/data",
- json={"status": True, "result": "1 item(s) updated"})
+ requests_mock.put(
+ f"https://api.tago.io/device/{deviceID}/data",
+ json={"status": True, "result": "1 item(s) updated"},
+ )
resources = Resources()
- response = resources.devices.editDeviceData(deviceID, {"id": "idOfTheRecord", "value": "new value", "unit": "new unit"})
+ response = resources.devices.editDeviceData(
+ deviceID, {"id": "idOfTheRecord", "value": "new value", "unit": "new unit"}
+ )
assert response == "1 item(s) updated"
assert isinstance(response, str)
@@ -45,11 +175,281 @@ def testDeleteDeviceDataMethod(requests_mock: Mocker) -> None:
"""
deviceID = "device1"
- requests_mock.delete(f"https://api.tago.io/device/{deviceID}/data",
- json={"status": True, "result": "2 Data Removed"})
+ requests_mock.delete(
+ f"https://api.tago.io/device/{deviceID}/data",
+ json={"status": True, "result": "2 Data Removed"},
+ )
resources = Resources()
- response = resources.devices.deleteDeviceData(deviceID, {"ids": ["recordIdToDelete", "anotherRecordIdToDelete"]})
+ response = resources.devices.deleteDeviceData(
+ deviceID, {"ids": ["recordIdToDelete", "anotherRecordIdToDelete"]}
+ )
assert response == "2 Data Removed"
assert isinstance(response, str)
+
+
+def testListDevice(requests_mock: Mocker) -> None:
+ """Test listDevice method of Devices class."""
+ mock_response = mockDeviceList()
+ requests_mock.get("https://api.tago.io/device", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.listDevice({"page": 1, "amount": 20})
+
+ assert isinstance(result, list)
+ assert len(result) > 0
+ assert result[0]["id"] == "device-id-123"
+
+
+def testCreateDevice(requests_mock: Mocker) -> None:
+ """Test create method of Devices class."""
+ mock_response = mockDeviceCreate()
+ requests_mock.post("https://api.tago.io/device", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.create(
+ {
+ "name": "New Device",
+ "network": "network-id-123",
+ "connector": "connector-id-123",
+ "type": "mutable",
+ }
+ )
+
+ assert result["device_id"] == "device-id-new"
+ assert result["token"] == "new-token-123"
+
+
+def testEditDevice(requests_mock: Mocker) -> None:
+ """Test edit method of Devices class."""
+ device_id = "device-id-123"
+ requests_mock.put(
+ f"https://api.tago.io/device/{device_id}",
+ json={"status": True, "result": "Successfully Updated"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.edit(device_id, {"name": "Updated Name"})
+
+ assert result == "Successfully Updated"
+
+
+def testDeleteDevice(requests_mock: Mocker) -> None:
+ """Test delete method of Devices class."""
+ device_id = "device-id-123"
+ requests_mock.delete(
+ f"https://api.tago.io/device/{device_id}",
+ json={"status": True, "result": "Successfully Removed"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.delete(device_id)
+
+ assert result == "Successfully Removed"
+
+
+def testDeviceInfo(requests_mock: Mocker) -> None:
+ """Test info method of Devices class."""
+ device_id = "device-id-123"
+ mock_response = mockDeviceInfo()
+ requests_mock.get(f"https://api.tago.io/device/{device_id}", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.info(device_id)
+
+ assert result["id"] == "device-id-123"
+ assert result["name"] == "Temperature Sensor"
+
+
+def testParamSet(requests_mock: Mocker) -> None:
+ """Test paramSet method of Devices class."""
+ device_id = "device-id-123"
+ requests_mock.post(
+ f"https://api.tago.io/device/{device_id}/params",
+ json={"status": True, "result": "Successfully Updated"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.paramSet(
+ device_id, {"key": "threshold", "value": "30", "sent": False}
+ )
+
+ assert result == "Successfully Updated"
+
+
+def testParamList(requests_mock: Mocker) -> None:
+ """Test paramList method of Devices class."""
+ device_id = "device-id-123"
+ mock_response = mockConfigParams()
+ requests_mock.get(
+ f"https://api.tago.io/device/{device_id}/params", json=mock_response
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.paramList(device_id)
+
+ assert isinstance(result, list)
+ assert result[0]["key"] == "threshold"
+
+
+def testParamRemove(requests_mock: Mocker) -> None:
+ """Test paramRemove method of Devices class."""
+ device_id = "device-id-123"
+ param_id = "param-id-123"
+ requests_mock.delete(
+ f"https://api.tago.io/device/{device_id}/params/{param_id}",
+ json={"status": True, "result": "Successfully Removed"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.paramRemove(device_id, param_id)
+
+ assert result == "Successfully Removed"
+
+
+def testTokenList(requests_mock: Mocker) -> None:
+ """Test tokenList method of Devices class."""
+ device_id = "device-id-123"
+ mock_response = mockTokenList()
+ requests_mock.get(
+ f"https://api.tago.io/device/token/{device_id}", json=mock_response
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.tokenList(device_id)
+
+ assert isinstance(result, list)
+ assert result[0]["token"] == "token-123"
+
+
+def testTokenCreate(requests_mock: Mocker) -> None:
+ """Test tokenCreate method of Devices class."""
+ mock_response = mockTokenCreate()
+ requests_mock.post("https://api.tago.io/device/token", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.tokenCreate(
+ "device-id-123", {"name": "New Token", "permission": "write"}
+ )
+
+ assert result["token"] == "new-token-456"
+
+
+def testTokenDelete(requests_mock: Mocker) -> None:
+ """Test tokenDelete method of Devices class."""
+ token = "token-to-delete"
+ requests_mock.delete(
+ f"https://api.tago.io/device/token/{token}",
+ json={"status": True, "result": "Successfully Removed"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.tokenDelete(token)
+
+ assert result == "Successfully Removed"
+
+
+def testGetDeviceData(requests_mock: Mocker) -> None:
+ """Test getDeviceData method of Devices class."""
+ device_id = "device-id-123"
+ mock_response = mockDeviceData()
+ requests_mock.get(
+ f"https://api.tago.io/device/{device_id}/data", json=mock_response
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.getDeviceData(device_id, {"variables": ["temperature"]})
+
+ assert isinstance(result, list)
+ assert result[0]["variable"] == "temperature"
+
+
+def testEmptyDeviceData(requests_mock: Mocker) -> None:
+ """Test emptyDeviceData method of Devices class."""
+ device_id = "device-id-123"
+ requests_mock.post(
+ f"https://api.tago.io/device/{device_id}/empty",
+ json={"status": True, "result": "All data removed"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.emptyDeviceData(device_id)
+
+ assert result == "All data removed"
+
+
+def testAmount(requests_mock: Mocker) -> None:
+ """Test amount method of Devices class."""
+ device_id = "device-id-123"
+ requests_mock.get(
+ f"https://api.tago.io/device/{device_id}/data_amount",
+ json={"status": True, "result": 15234},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.amount(device_id)
+
+ assert result == 15234
+
+
+def testGetChunk(requests_mock: Mocker) -> None:
+ """Test getChunk method of Devices class."""
+ device_id = "device-id-123"
+ mock_response = mockChunkList()
+ requests_mock.get(
+ f"https://api.tago.io/device/{device_id}/chunk", json=mock_response
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.getChunk(device_id)
+
+ assert isinstance(result, list)
+ assert result[0]["amount"] == 1000
+
+
+def testDeleteChunk(requests_mock: Mocker) -> None:
+ """Test deleteChunk method of Devices class."""
+ device_id = "device-id-123"
+ chunk_id = "chunk-id-456"
+ requests_mock.delete(
+ f"https://api.tago.io/device/{device_id}/chunk/{chunk_id}",
+ json={"status": True, "result": f"Chunk {chunk_id} deleted"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.deleteChunk(device_id, chunk_id)
+
+ assert result == f"Chunk {chunk_id} deleted"
+
+
+def testDataBackup(requests_mock: Mocker) -> None:
+ """Test dataBackup method of Devices class."""
+ device_id = "device-id-123"
+ mock_response = mockBackupResponse()
+ requests_mock.post(
+ f"https://api.tago.io/device/{device_id}/data/backup", json=mock_response
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.dataBackup(
+ {"deviceID": device_id, "file_address": "/backups/backup.csv", "headers": True}
+ )
+
+ assert result["file_address"] == "/backups/device-123/backup.csv"
+
+
+def testDataRestore(requests_mock: Mocker) -> None:
+ """Test dataRestore method of Devices class."""
+ device_id = "device-id-123"
+ requests_mock.post(
+ f"https://api.tago.io/device/{device_id}/data/restore",
+ json={"status": True, "result": "Data import added to the queue successfully!"},
+ )
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.devices.dataRestore(
+ {"deviceID": device_id, "file_address": "/backups/restore.csv"}
+ )
+
+ assert result == "Data import added to the queue successfully!"
diff --git a/tests/Resources/test_integration_network.py b/tests/Resources/test_integration_network.py
index 35e4516..4c1aea7 100644
--- a/tests/Resources/test_integration_network.py
+++ b/tests/Resources/test_integration_network.py
@@ -1,39 +1,236 @@
-from requests_mock.mocker import Mocker
+from typing import Any
+from typing import Dict
+from requests_mock.mocker import Mocker
from src.tagoio_sdk.modules.Resources.IntegrationNetwork import Networks
-from tests.conftest import mockListNetwork, mockNetworkInfo
-def testNetworksMethodListNetworks(
- requests_mock: Mocker, mockListNetwork: mockListNetwork
-):
- """
- :param requests_mock are a plugin of pytest to mock the requests.
- :param mockListNetwork is a fixture to return list of NetworkInfo.
- """
+def mockListNetwork() -> Dict[str, Any]:
+ """Mock to return the list of NetworkInfo."""
+ return {
+ "status": True,
+ "result": [
+ {"id": "60af66df0ae39d0012b0bbe9", "name": "AWS IoT"},
+ {"id": "5d48632019b67f001c874a6b", "name": "BeWhere"},
+ ],
+ }
+
+
+def mockNetworkInfo() -> Dict[str, Any]:
+ """Mock to return the object NetworkInfo."""
+ return {
+ "status": True,
+ "result": {
+ "id": "5ede22a7427104001c248b08",
+ "name": "LoRaWAN Activity",
+ "profile": "5bbcb03b667d7a002e56664b",
+ "middleware_endpoint": "https://lorawan.tago.io",
+ },
+ }
+
+
+def mockNetworkCreate() -> Dict[str, Any]:
+ """Mock to return network create response."""
+ return {
+ "status": True,
+ "result": {"network": "network-id-123"},
+ }
+
+
+def mockNetworkEdit() -> Dict[str, Any]:
+ """Mock to return network edit response."""
+ return {
+ "status": True,
+ "result": "Successfully Updated",
+ }
+
+
+def mockNetworkDelete() -> Dict[str, Any]:
+ """Mock to return network delete response."""
+ return {
+ "status": True,
+ "result": "Successfully Removed",
+ }
+
+
+def mockNetworkTokenList() -> Dict[str, Any]:
+ """Mock to return list of network tokens."""
+ return {
+ "status": True,
+ "result": [
+ {
+ "token": "token-123",
+ "name": "Default Token",
+ "permission": "full",
+ "created_at": "2025-01-09T10:00:00.000Z",
+ },
+ {
+ "token": "token-456",
+ "name": "Read-Only Token",
+ "permission": "read",
+ "created_at": "2025-01-08T15:30:00.000Z",
+ },
+ ],
+ }
+
+
+def mockNetworkTokenCreate() -> Dict[str, Any]:
+ """Mock to return token create response."""
+ return {
+ "status": True,
+ "result": {
+ "token": "new-token-value",
+ "expire_date": None,
+ },
+ }
+
- requests_mock.get("https://api.tago.io/integration/network", json=mockListNetwork)
+def mockNetworkTokenDelete() -> Dict[str, Any]:
+ """Mock to return token delete response."""
+ return {
+ "status": True,
+ "result": "Successfully Removed",
+ }
+
+
+def testNetworksMethodListNetworks(requests_mock: Mocker):
+ """Test listNetwork method with pagination."""
+ requests_mock.get("https://api.tago.io/integration/network", json=mockListNetwork())
tokenFake = {"token": "fake_token"}
response = Networks(params=tokenFake).listNetwork(queryObj={"amount": 100})
- assert response == mockListNetwork["result"]
+ assert response == mockListNetwork()["result"]
assert isinstance(response, list)
assert isinstance(response[0], dict)
-def testNetworksMethodInfo(requests_mock: Mocker, mockNetworkInfo: mockNetworkInfo):
- """
- :param requests_mock are a plugin of pytest to mock the requests.
- :param mockNetworkInfo is a fixture to return the object NetworkInfo.
- """
+def testNetworksMethodInfo(requests_mock: Mocker):
+ """Test info method to retrieve network details."""
networkID = "fake_network_id"
requests_mock.get(
- f"https://api.tago.io/integration/network/{networkID}", json=mockNetworkInfo
+ f"https://api.tago.io/integration/network/{networkID}", json=mockNetworkInfo()
)
tokenFake = {"token": "fake_token"}
response = Networks(params=tokenFake).info(networkID=networkID)
- assert response == mockNetworkInfo["result"]
+ assert response == mockNetworkInfo()["result"]
+ assert isinstance(response, dict)
+
+
+def testNetworksMethodCreate(requests_mock: Mocker):
+ """Test create method to create a new network."""
+ requests_mock.post("https://api.tago.io/integration/network", json=mockNetworkCreate())
+
+ tokenFake = {"token": "fake_token"}
+ response = Networks(params=tokenFake).create(
+ {
+ "name": "My Custom Network",
+ "description": "Custom integration network",
+ "middleware_endpoint": "https://my-middleware.com/endpoint",
+ "public": False,
+ }
+ )
+
+ assert response == mockNetworkCreate()["result"]
+ assert isinstance(response, dict)
+ assert "network" in response
+
+
+def testNetworksMethodEdit(requests_mock: Mocker):
+ """Test edit method to update network properties."""
+ networkID = "network-id-123"
+ requests_mock.put(
+ f"https://api.tago.io/integration/network/{networkID}", json=mockNetworkEdit()
+ )
+
+ tokenFake = {"token": "fake_token"}
+ response = Networks(params=tokenFake).edit(
+ networkID,
+ {
+ "name": "Updated Network Name",
+ "description": "Updated description",
+ "public": True,
+ },
+ )
+
+ assert response == mockNetworkEdit()["result"]
+ assert response == "Successfully Updated"
+
+
+def testNetworksMethodDelete(requests_mock: Mocker):
+ """Test delete method to remove a network."""
+ networkID = "network-id-123"
+ requests_mock.delete(
+ f"https://api.tago.io/integration/network/{networkID}", json=mockNetworkDelete()
+ )
+
+ tokenFake = {"token": "fake_token"}
+ response = Networks(params=tokenFake).delete(networkID)
+
+ assert response == mockNetworkDelete()["result"]
+ assert response == "Successfully Removed"
+
+
+def testNetworksMethodTokenList(requests_mock: Mocker):
+ """Test tokenList method to retrieve network tokens."""
+ networkID = "network-id-123"
+ requests_mock.get(
+ f"https://api.tago.io/integration/network/token/{networkID}",
+ json=mockNetworkTokenList(),
+ )
+
+ tokenFake = {"token": "fake_token"}
+ response = Networks(params=tokenFake).tokenList(
+ networkID,
+ {
+ "page": 1,
+ "amount": 20,
+ "fields": ["name", "token", "permission"],
+ "orderBy": ["created_at", "desc"],
+ },
+ )
+
+ # dateParserList converts created_at strings to datetime objects
+ assert isinstance(response, list)
+ assert len(response) == 2
+ assert response[0]["token"] == "token-123"
+ assert response[0]["name"] == "Default Token"
+ assert response[0]["permission"] == "full"
+
+
+def testNetworksMethodTokenCreate(requests_mock: Mocker):
+ """Test tokenCreate method to generate a new token."""
+ requests_mock.post(
+ "https://api.tago.io/integration/network/token", json=mockNetworkTokenCreate()
+ )
+
+ tokenFake = {"token": "fake_token"}
+ response = Networks(params=tokenFake).tokenCreate(
+ "network-id-123",
+ {
+ "name": "Production Token",
+ "permission": "write",
+ "expire_time": "never",
+ },
+ )
+
+ assert response == mockNetworkTokenCreate()["result"]
assert isinstance(response, dict)
+ assert "token" in response
+
+
+def testNetworksMethodTokenDelete(requests_mock: Mocker):
+ """Test tokenDelete method to remove a token."""
+ token = "token-to-delete"
+ requests_mock.delete(
+ f"https://api.tago.io/integration/network/token/{token}",
+ json=mockNetworkTokenDelete(),
+ )
+
+ tokenFake = {"token": "fake_token"}
+ response = Networks(params=tokenFake).tokenDelete(token)
+
+ assert response == mockNetworkTokenDelete()["result"]
+ assert response == "Successfully Removed"
diff --git a/tests/Resources/test_profile.py b/tests/Resources/test_profile.py
index 784238f..463312f 100644
--- a/tests/Resources/test_profile.py
+++ b/tests/Resources/test_profile.py
@@ -1,8 +1,10 @@
import os
+
from requests_mock.mocker import Mocker
from tagoio_sdk.common.Common_Type import TokenDataList
-from tagoio_sdk.modules.Resources.Profile_Type import ProfileInfo, ProfileSummary
+from tagoio_sdk.modules.Resources.Profile_Type import ProfileInfo
+from tagoio_sdk.modules.Resources.Profile_Type import ProfileSummary
from tagoio_sdk.modules.Resources.Resources import Resources
@@ -187,3 +189,306 @@ def testProfileMethodTokenList(requests_mock: Mocker) -> None:
assert response[1]["token"] == mockTokenDataList()["result"][1]["token"]
assert isinstance(response, list)
assert isinstance(response[1], dict)
+
+
+def mockProfileCreate() -> dict:
+ return {"status": True, "result": {"id": "new-profile-id-123"}}
+
+
+def mockProfileEdit() -> dict:
+ return {"status": True, "result": "Successfully Updated"}
+
+
+def mockProfileDelete() -> dict:
+ return {"status": True, "result": "Successfully Removed"}
+
+
+def mockUsageStatisticList() -> dict:
+ return {
+ "status": True,
+ "result": [
+ {
+ "time": "2024-09-02T00:01:29.749Z",
+ "analysis": 0.07,
+ "data_records": 67254,
+ "input": 1500,
+ "output": 250,
+ },
+ {
+ "time": "2024-09-03T00:01:29.749Z",
+ "analysis": 0.12,
+ "data_records": 85123,
+ "input": 2100,
+ "output": 340,
+ },
+ ],
+ }
+
+
+def mockAuditLog() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "events": [
+ {
+ "resourceName": "device",
+ "message": "Device created",
+ "resourceID": "device-id-123",
+ "who": "account-id-456",
+ "date": "2024-12-01T10:00:00.000Z",
+ }
+ ],
+ "statistics": {
+ "recordsMatched": 1,
+ "recordsScanned": 100,
+ "bytesScanned": 5000,
+ },
+ "status": "Complete",
+ "queryId": "query-id-789",
+ },
+ }
+
+
+def mockAddonInfo() -> dict:
+ return {
+ "status": True,
+ "result": {"id": "addon-id-123", "name": "Custom DNS", "logo_url": None},
+ }
+
+
+def mockServiceEdit() -> dict:
+ return {"status": True, "result": "Profile resource allocation Successfully Updated"}
+
+
+def mockTransferToken() -> dict:
+ return {"status": True, "result": "Token Successfully Transferred"}
+
+
+def mockTokenCreate() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "token": "new-token-value",
+ "name": "API Access",
+ "permission": "full",
+ "expire_date": "2025-12-31T23:59:59.000Z",
+ },
+ }
+
+
+def mockTokenDelete() -> dict:
+ return {"status": True, "result": "Token Successfully Removed"}
+
+
+def mockTeamList() -> dict:
+ return {
+ "status": True,
+ "result": [
+ {
+ "id": "account-id-123",
+ "active": False,
+ "name": "John Doe",
+ "email": "john@example.com",
+ "created_at": "2024-01-01T10:00:00.000Z",
+ },
+ {
+ "id": "account-id-456",
+ "active": True,
+ "name": "Jane Smith",
+ "email": "jane@example.com",
+ "created_at": "2024-02-01T10:00:00.000Z",
+ },
+ ],
+ }
+
+
+def mockAddTeamMember() -> dict:
+ return {"status": True, "result": "User invited"}
+
+
+def mockDeleteTeamMember() -> dict:
+ return {"status": True, "result": "Account Successfully Removed"}
+
+
+def testProfileMethodCreate(requests_mock: Mocker) -> None:
+ """Test profile creation"""
+ requests_mock.post("https://api.tago.io/profile/", json=mockProfileCreate())
+
+ resources = Resources()
+ response = resources.profile.create(
+ {"name": "New Profile"}, allocate_free_resources=True
+ )
+
+ assert response["id"] == mockProfileCreate()["result"]["id"]
+ assert isinstance(response, dict)
+
+
+def testProfileMethodEdit(requests_mock: Mocker) -> None:
+ """Test profile editing"""
+ requests_mock.put(
+ "https://api.tago.io/profile/profile-id-123", json=mockProfileEdit()
+ )
+
+ resources = Resources()
+ response = resources.profile.edit("profile-id-123", {"name": "Updated Name"})
+
+ assert response == mockProfileEdit()["result"]
+ assert isinstance(response, str)
+
+
+def testProfileMethodDelete(requests_mock: Mocker) -> None:
+ """Test profile deletion"""
+ requests_mock.delete(
+ "https://api.tago.io/profile/profile-id-123", json=mockProfileDelete()
+ )
+
+ resources = Resources()
+ response = resources.profile.delete(
+ "profile-id-123", {"password": "test-password"}
+ )
+
+ assert response == mockProfileDelete()["result"]
+ assert isinstance(response, str)
+
+
+def testProfileMethodUsageStatisticList(requests_mock: Mocker) -> None:
+ """Test usage statistics listing"""
+ requests_mock.get(
+ "https://api.tago.io/profile/profile-id-123/statistics",
+ json=mockUsageStatisticList(),
+ )
+
+ resources = Resources()
+ response = resources.profile.usageStatisticList("profile-id-123")
+
+ assert len(response) == 2
+ assert response[0]["analysis"] == 0.07
+ assert isinstance(response, list)
+
+
+def testProfileMethodAuditLog(requests_mock: Mocker) -> None:
+ """Test audit log creation"""
+ requests_mock.get(
+ "https://api.tago.io/profile/profile-id-123/auditlog", json=mockAuditLog()
+ )
+
+ resources = Resources()
+ response = resources.profile.auditLog("profile-id-123")
+
+ assert response["queryId"] == mockAuditLog()["result"]["queryId"]
+ assert response["status"] == "Complete"
+ assert isinstance(response, dict)
+
+
+def testProfileMethodAuditLogQuery(requests_mock: Mocker) -> None:
+ """Test audit log query"""
+ requests_mock.get(
+ "https://api.tago.io/profile/profile-id-123/auditlog/query-id-789",
+ json=mockAuditLog(),
+ )
+
+ resources = Resources()
+ response = resources.profile.auditLogQuery("profile-id-123", "query-id-789")
+
+ assert response["queryId"] == mockAuditLog()["result"]["queryId"]
+ assert isinstance(response, dict)
+
+
+def testProfileMethodServiceEdit(requests_mock: Mocker) -> None:
+ """Test service editing"""
+ requests_mock.post(
+ "https://api.tago.io/profile/profile-id-123/services", json=mockServiceEdit()
+ )
+
+ resources = Resources()
+ response = resources.profile.serviceEdit(
+ "profile-id-123", {"input": 350000, "output": 342153}
+ )
+
+ assert response == mockServiceEdit()["result"]
+ assert isinstance(response, str)
+
+
+def testProfileMethodTransferToken(requests_mock: Mocker) -> None:
+ """Test token transfer"""
+ requests_mock.put(
+ "https://api.tago.io/profile/switch/target-profile-123",
+ json=mockTransferToken(),
+ )
+
+ resources = Resources()
+ response = resources.profile.transferTokenToAnotherProfile("target-profile-123")
+
+ assert response == mockTransferToken()["result"]
+ assert isinstance(response, str)
+
+
+def testProfileMethodTokenCreate(requests_mock: Mocker) -> None:
+ """Test token creation"""
+ requests_mock.post(
+ "https://api.tago.io/profile/profile-id-123/token", json=mockTokenCreate()
+ )
+
+ resources = Resources()
+ response = resources.profile.tokenCreate(
+ "profile-id-123",
+ {"name": "API Access", "permission": "full", "email": "test@example.com"},
+ )
+
+ assert response["token"] == mockTokenCreate()["result"]["token"]
+ assert isinstance(response, dict)
+
+
+def testProfileMethodTokenDelete(requests_mock: Mocker) -> None:
+ """Test token deletion"""
+ requests_mock.delete(
+ "https://api.tago.io/profile/profile-id-123/token/token-xyz",
+ json=mockTokenDelete(),
+ )
+
+ resources = Resources()
+ response = resources.profile.tokenDelete("profile-id-123", "token-xyz")
+
+ assert response == mockTokenDelete()["result"]
+ assert isinstance(response, str)
+
+
+def testProfileMethodAddTeamMember(requests_mock: Mocker) -> None:
+ """Test adding team member"""
+ requests_mock.post(
+ "https://api.tago.io/profile/profile-id-123/team", json=mockAddTeamMember()
+ )
+
+ resources = Resources()
+ response = resources.profile.addTeamMember("profile-id-123", "user@example.com")
+
+ assert response == mockAddTeamMember()["result"]
+ assert isinstance(response, str)
+
+
+def testProfileMethodTeamList(requests_mock: Mocker) -> None:
+ """Test team member listing"""
+ requests_mock.get(
+ "https://api.tago.io/profile/profile-id-123/team", json=mockTeamList()
+ )
+
+ resources = Resources()
+ response = resources.profile.teamList("profile-id-123")
+
+ assert len(response) == 2
+ assert response[0]["name"] == "John Doe"
+ assert isinstance(response, list)
+
+
+def testProfileMethodDeleteTeamMember(requests_mock: Mocker) -> None:
+ """Test team member deletion"""
+ requests_mock.delete(
+ "https://api.tago.io/profile/profile-id-123/team/account-id-456",
+ json=mockDeleteTeamMember(),
+ )
+
+ resources = Resources()
+ response = resources.profile.deleteTeamMember("profile-id-123", "account-id-456")
+
+ assert response == mockDeleteTeamMember()["result"]
+ assert isinstance(response, str)
diff --git a/tests/Resources/test_run.py b/tests/Resources/test_run.py
new file mode 100644
index 0000000..67216d8
--- /dev/null
+++ b/tests/Resources/test_run.py
@@ -0,0 +1,421 @@
+import os
+
+from requests_mock.mocker import Mocker
+
+from tagoio_sdk.modules.Resources.Resources import Resources
+
+
+os.environ["T_ANALYSIS_TOKEN"] = "your_token_value"
+
+
+def mockRunInfo() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "profile": "profile_id_123",
+ "active": True,
+ "name": "My Run Environment",
+ "sub_title": "IoT Application",
+ "url": "myapp.run.tago.io",
+ "email_domain": None,
+ "signup_method": "default",
+ "favicon": None,
+ "logo": "https://example.com/logo.png",
+ "signup_logo": None,
+ "signup_logo_options": {},
+ "sidebar_buttons": [],
+ "signup_fields": [],
+ "email_templates": {},
+ "feature_devicewifisetup": {},
+ "feature_geolocation": {},
+ "theme": {},
+ "integration": {},
+ "sso_saml_active": False,
+ "security": {},
+ },
+ }
+
+
+def mockRunEdit() -> dict:
+ return {"status": True, "result": "TagoIO Run Successfully Updated"}
+
+
+def mockUserList() -> dict:
+ return {
+ "status": True,
+ "result": [
+ {
+ "id": "user_id_1",
+ "name": "John Doe",
+ "email": "john@example.com",
+ "timezone": "America/New_York",
+ "created_at": "2023-02-21T15:17:35.759Z",
+ "updated_at": "2023-02-21T15:17:35.759Z",
+ "last_login": "2023-02-21T15:17:35.759Z",
+ },
+ {
+ "id": "user_id_2",
+ "name": "Jane Smith",
+ "email": "jane@example.com",
+ "timezone": "America/Los_Angeles",
+ "created_at": "2023-02-21T16:17:35.759Z",
+ "updated_at": "2023-02-21T16:17:35.759Z",
+ "last_login": "2023-02-21T16:17:35.759Z",
+ },
+ ],
+ }
+
+
+def mockUserInfo() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "id": "user_id_1",
+ "name": "John Doe",
+ "email": "john@example.com",
+ "timezone": "America/New_York",
+ "company": "ACME Corp",
+ "phone": "+1234567890",
+ "language": "en-US",
+ "profile": "profile_id_123",
+ "active": True,
+ "newsletter": False,
+ "last_login": "2023-02-21T15:17:35.759Z",
+ "created_at": "2023-02-21T15:17:35.759Z",
+ "updated_at": "2023-02-21T15:17:35.759Z",
+ "options": {},
+ "tags": [{"key": "role", "value": "admin"}],
+ },
+ }
+
+
+def mockUserCreate() -> dict:
+ return {"status": True, "result": {"user": "user_id_new"}}
+
+
+def mockUserEdit() -> dict:
+ return {"status": True, "result": "TagoIO Run User Successfully Updated"}
+
+
+def mockUserDelete() -> dict:
+ return {"status": True, "result": "Successfully Removed"}
+
+
+def mockLoginAsUser() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...",
+ "expire_date": "2024-02-21T15:17:35.759Z",
+ },
+ }
+
+
+def mockEmailTest() -> dict:
+ return {"status": True, "result": "E-mail sent to example@email.com"}
+
+
+def mockNotificationList() -> dict:
+ return {
+ "status": True,
+ "result": [
+ {
+ "id": "notification_id_1",
+ "title": "System Update",
+ "message": "New features available",
+ },
+ {
+ "id": "notification_id_2",
+ "title": "Maintenance",
+ "message": "Scheduled maintenance tonight",
+ },
+ ],
+ }
+
+
+def mockNotificationCreate() -> dict:
+ return {"status": True, "result": {"id": "notification_id_new"}}
+
+
+def mockNotificationEdit() -> dict:
+ return {"status": True, "result": "TagoIO Notification User Successfully Updated"}
+
+
+def mockNotificationDelete() -> dict:
+ return {"status": True, "result": "Successfully Removed"}
+
+
+def mockSSOSAMLInfo() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "sp": {
+ "entity_id": "https://example.com",
+ "acs_url": "https://example.com/acs",
+ "metadata": "...",
+ },
+ "idp": {"issuer": "https://idp.example.com"},
+ "mapping": {"email": "email", "firstName": "firstName"},
+ },
+ }
+
+
+def mockSSOSAMLEdit() -> dict:
+ return {"status": True, "result": "TagoIO Run SAML SSO Successfully Updated"}
+
+
+def mockCustomDomainCreate() -> dict:
+ return {"status": True, "result": "Custom domain created successfully"}
+
+
+def mockCustomDomainInfo() -> dict:
+ return {
+ "status": True,
+ "result": {
+ "active": True,
+ "domain": "mycompany.com",
+ "subdomain": "app",
+ "email": "app.mycompany.com",
+ "dns_ssl": {"status": True, "type": "TXT", "key": "key1", "value": "value1"},
+ "dns_page": {"status": True, "type": "CNAME", "key": "key2", "value": "value2"},
+ "dns_email_1": {"status": True, "type": "MX", "key": "key3", "value": "value3"},
+ "dns_email_2": {"status": True, "type": "TXT", "key": "key4", "value": "value4"},
+ "dns_email_3": {"status": True, "type": "TXT", "key": "key5", "value": "value5"},
+ "created_at": "2023-02-21T15:17:35.759Z",
+ },
+ }
+
+
+def mockCustomDomainDelete() -> dict:
+ return {"status": True, "result": "Custom domain deleted successfully"}
+
+
+def mockCustomDomainRegenerate() -> dict:
+ return {"status": True, "result": "Custom domain regenerated successfully"}
+
+
+def testRunMethodInfo(requests_mock: Mocker) -> None:
+ """Test info method of Run class."""
+ mock_response = mockRunInfo()
+ requests_mock.get("https://api.tago.io/run", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.info()
+
+ assert result["name"] == "My Run Environment"
+ assert result["active"] is True
+
+
+def testRunMethodEdit(requests_mock: Mocker) -> None:
+ """Test edit method of Run class."""
+ mock_response = mockRunEdit()
+ requests_mock.put("https://api.tago.io/run", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.edit({"name": "Updated Name"})
+
+ assert result == "TagoIO Run Successfully Updated"
+
+
+def testRunMethodListUsers(requests_mock: Mocker) -> None:
+ """Test listUsers method of Run class."""
+ mock_response = mockUserList()
+ requests_mock.get("https://api.tago.io/run/users", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.listUsers({"page": 1, "amount": 20})
+
+ assert isinstance(result, list)
+ assert len(result) == 2
+ assert result[0]["id"] == "user_id_1"
+ assert result[1]["id"] == "user_id_2"
+
+
+def testRunMethodUserInfo(requests_mock: Mocker) -> None:
+ """Test userInfo method of Run class."""
+ mock_response = mockUserInfo()
+ requests_mock.get("https://api.tago.io/run/users/user_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.userInfo("user_id_1")
+
+ assert result["id"] == "user_id_1"
+ assert result["name"] == "John Doe"
+ assert result["email"] == "john@example.com"
+
+
+def testRunMethodUserCreate(requests_mock: Mocker) -> None:
+ """Test userCreate method of Run class."""
+ mock_response = mockUserCreate()
+ requests_mock.post("https://api.tago.io/run/users", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.userCreate(
+ {
+ "name": "New User",
+ "email": "newuser@example.com",
+ "password": "secure123",
+ "timezone": "America/New_York",
+ }
+ )
+
+ assert result["user"] == "user_id_new"
+
+
+def testRunMethodUserEdit(requests_mock: Mocker) -> None:
+ """Test userEdit method of Run class."""
+ mock_response = mockUserEdit()
+ requests_mock.put("https://api.tago.io/run/users/user_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.userEdit("user_id_1", {"name": "Updated Name"})
+
+ assert result == "TagoIO Run User Successfully Updated"
+
+
+def testRunMethodUserDelete(requests_mock: Mocker) -> None:
+ """Test userDelete method of Run class."""
+ mock_response = mockUserDelete()
+ requests_mock.delete("https://api.tago.io/run/users/user_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.userDelete("user_id_1")
+
+ assert result == "Successfully Removed"
+
+
+def testRunMethodLoginAsUser(requests_mock: Mocker) -> None:
+ """Test loginAsUser method of Run class."""
+ mock_response = mockLoginAsUser()
+ requests_mock.get("https://api.tago.io/run/users/user_id_1/login", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.loginAsUser("user_id_1")
+
+ assert "token" in result
+ assert result["token"].startswith("eyJ")
+
+
+def testRunMethodEmailTest(requests_mock: Mocker) -> None:
+ """Test emailTest method of Run class."""
+ mock_response = mockEmailTest()
+ requests_mock.post("https://api.tago.io/run/email_test", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.emailTest({"subject": "Test", "body": "Test message"})
+
+ assert result == "E-mail sent to example@email.com"
+
+
+def testRunMethodNotificationList(requests_mock: Mocker) -> None:
+ """Test notificationList method of Run class."""
+ mock_response = mockNotificationList()
+ requests_mock.get("https://api.tago.io/run/notification/user_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.notificationList("user_id_1")
+
+ assert isinstance(result, list)
+ assert len(result) == 2
+ assert result[0]["id"] == "notification_id_1"
+
+
+def testRunMethodNotificationCreate(requests_mock: Mocker) -> None:
+ """Test notificationCreate method of Run class."""
+ mock_response = mockNotificationCreate()
+ requests_mock.post("https://api.tago.io/run/notification/", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.notificationCreate("user_id_1", {"title": "Alert", "message": "Important message"})
+
+ assert result["id"] == "notification_id_new"
+
+
+def testRunMethodNotificationEdit(requests_mock: Mocker) -> None:
+ """Test notificationEdit method of Run class."""
+ mock_response = mockNotificationEdit()
+ requests_mock.put("https://api.tago.io/run/notification/notification_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.notificationEdit("notification_id_1", {"title": "Updated Title"})
+
+ assert result == "TagoIO Notification User Successfully Updated"
+
+
+def testRunMethodNotificationDelete(requests_mock: Mocker) -> None:
+ """Test notificationDelete method of Run class."""
+ mock_response = mockNotificationDelete()
+ requests_mock.delete("https://api.tago.io/run/notification/notification_id_1", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.notificationDelete("notification_id_1")
+
+ assert result == "Successfully Removed"
+
+
+def testRunMethodSSOSAMLInfo(requests_mock: Mocker) -> None:
+ """Test ssoSAMLInfo method of Run class."""
+ mock_response = mockSSOSAMLInfo()
+ requests_mock.get("https://api.tago.io/run/sso/saml", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.ssoSAMLInfo()
+
+ assert "sp" in result
+ assert "idp" in result
+
+
+def testRunMethodSSOSAMLEdit(requests_mock: Mocker) -> None:
+ """Test ssoSAMLEdit method of Run class."""
+ mock_response = mockSSOSAMLEdit()
+ requests_mock.put("https://api.tago.io/run/sso/saml", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.ssoSAMLEdit({"active": True, "idp_metadata": "..."})
+
+ assert result == "TagoIO Run SAML SSO Successfully Updated"
+
+
+def testRunMethodCreateCustomDomain(requests_mock: Mocker) -> None:
+ """Test createCustomDomain method of Run class."""
+ mock_response = mockCustomDomainCreate()
+ requests_mock.post("https://api.tago.io/run/customdomain/profile_id_123", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.createCustomDomain("profile_id_123", {"domain": "mycompany.com", "subdomain": "app"})
+
+ assert result == "Custom domain created successfully"
+
+
+def testRunMethodGetCustomDomain(requests_mock: Mocker) -> None:
+ """Test getCustomDomain method of Run class."""
+ mock_response = mockCustomDomainInfo()
+ requests_mock.get("https://api.tago.io/run/customdomain/profile_id_123", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.getCustomDomain("profile_id_123")
+
+ assert result["domain"] == "mycompany.com"
+ assert result["active"] is True
+
+
+def testRunMethodDeleteCustomDomain(requests_mock: Mocker) -> None:
+ """Test deleteCustomDomain method of Run class."""
+ mock_response = mockCustomDomainDelete()
+ requests_mock.delete("https://api.tago.io/run/customdomain/profile_id_123", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.deleteCustomDomain("profile_id_123")
+
+ assert result == "Custom domain deleted successfully"
+
+
+def testRunMethodRegenerateCustomDomain(requests_mock: Mocker) -> None:
+ """Test regenerateCustomDomain method of Run class."""
+ mock_response = mockCustomDomainRegenerate()
+ requests_mock.put("https://api.tago.io/run/customdomain/regenerate/profile_id_123", json=mock_response)
+
+ resources = Resources({"token": "your_token_value"})
+ result = resources.run.regenerateCustomDomain("profile_id_123")
+
+ assert result == "Custom domain regenerated successfully"