Skip to content

Provisioning Module

Python API reference for the tlm_cli.manufacturing.provisioning package.

Use this package to provision, unprovision, and retrieve agent configuration files for devices programmatically. DeviceProvisioner drives the full device lifecycle; the request and result models define the inputs and outputs for each operation; the exception hierarchy lets you handle specific failure modes precisely.

For a conceptual explanation of what provisioning does, see Provisioning Workflow.


DeviceProvisioner

tlm_cli.manufacturing.provisioning.device.DeviceProvisioner

Provisioning service for devices in PMS.

Orchestrates the full provisioning lifecycle across PMS (JSON:API), IoT, and ToloMEO Manager (plain REST via httpx2).

Parameters:

Name Type Description Default
pms_client PMSClient

PMS JSON:API client for customer and device operations.

required
iot_client RestClientProtocol

Authenticated REST client for the IoT endpoint.

required
tolomeo_client RestClientProtocol

Authenticated REST client for the ToloMEO manager endpoint.

required
instance str

Instance name, e.g. "tolomeo.io". Used in generated config files.

required

Examples:

>>> provisioner = DeviceProvisioner(pms_client, iot_client, tolomeo_client, "tolomeo.io")
>>> result = provisioner.provision(ProvisioningRequest(serial_number="DEV123", customer_code="ACME"))
Source code in tlm_cli/manufacturing/provisioning/device.py
class DeviceProvisioner:
    """Provisioning service for devices in PMS.

    Orchestrates the full provisioning lifecycle across PMS (JSON:API),
    IoT, and ToloMEO Manager (plain REST via httpx2).

    Args:
        pms_client: PMS JSON:API client for customer and device operations.
        iot_client: Authenticated REST client for the IoT endpoint.
        tolomeo_client: Authenticated REST client for the ToloMEO manager endpoint.
        instance: Instance name, e.g. "tolomeo.io". Used in generated config files.

    Examples:
        >>> provisioner = DeviceProvisioner(pms_client, iot_client, tolomeo_client, "tolomeo.io")
        >>> result = provisioner.provision(ProvisioningRequest(serial_number="DEV123", customer_code="ACME"))
    """

    _logger = logger.getChild(__qualname__)

    CONFIG_TEMPLATE = """# Configuration file for {serial_number}. Place into /opt/connhex/configs/

CONNHEX_AGENT_LICENSE_AGENT_HOST=https://registry.compiuta.com
CONNHEX_AGENT_INIT_HOST=https://apis.{instance}
CONNHEX_AGENT_INIT_ID={serial_number}
CONNHEX_AGENT_INIT_KEY={init_key}
"""

    def __init__(
        self,
        pms_client: PMSClient,
        iot_client: RestClientProtocol,
        tolomeo_client: RestClientProtocol,
        instance: str,
    ):
        self._pms_client = pms_client
        self._iot_client = iot_client
        self._tolomeo_client = tolomeo_client
        self._instance = instance

    def provision(self, request: ProvisioningRequest) -> ProvisioningResult:
        """Provision a device and write its agent configuration file.

        Executes the full provisioning sequence: verifies the device does not
        already exist, resolves the customer tenant ID, calls the bulk provisioning
        API, fetches the ConnHex ID from PMS, retrieves the init key from the IoT
        API, and writes the agent.env config file to disk.

        Args:
            request: Provisioning request containing serial number, customer code,
                and output path for the configuration file.

        Returns:
            ProvisioningResult with status SUCCESS and the written config file path,
            or status FAILED with an error message on any failure.

        Note:
            Failures are not raised (DeviceAlreadyExistsError, CustomerNotFoundError, DeviceProvisioningError,
            CertificateRetrievalError, ConfigurationError); they are returned as status FAILED with the cause in
            ``error_message``.
        """
        self._logger.info("Starting provisioning for device %s", request.serial_number)
        try:
            if self._pms_client.device.exists("serial_number", request.serial_number):
                raise DeviceAlreadyExistsError(f"Device {request.serial_number} already exists in manufacturing")

            tenant_id = self._get_tenant_id(request.customer_code)
            self._provision_device_bulk(request.serial_number, tenant_id, request.manufacturing_data)
            connhex_id = self._get_device_connhex_id(request.serial_number)
            init_key = self._get_device_init_key(connhex_id)
            config_file_path = self._create_config_file(request.serial_number, init_key, request.config_output_path)

            self._logger.info("Successfully provisioned device %s", request.serial_number)
            return ProvisioningResult(
                status=ProvisioningStatus.SUCCESS,
                serial_number=request.serial_number,
                connhex_id=connhex_id,
                config_file_path=config_file_path,
                tenant_id=tenant_id,
            )
        except Exception as e:
            self._logger.error("Provisioning failed for device %s: %s", request.serial_number, str(e))
            return ProvisioningResult(
                status=ProvisioningStatus.FAILED,
                serial_number=request.serial_number,
                error_message=str(e),
            )

    def unprovision(self, request: UnprovisioningRequest) -> UnprovisioningResult:
        """Permanently remove all provisioning records for a device via the bulk API.

        Args:
            request: Unprovisioning request containing the device serial number.

        Returns:
            UnprovisioningResult with status SUCCESS, or status FAILED with an
            error message on any failure.

        Note:
            Failures are not raised (DeviceNotFoundError, UnprovisioningError); they are returned as status FAILED with
            the cause in ``error_message``.
        """
        self._logger.info("Starting unprovisioning for device %s", request.serial_number)
        try:
            if not self._pms_client.device.exists("serial_number", request.serial_number):
                raise DeviceNotFoundError(f"Device {request.serial_number} not found in manufacturing")

            self._unprovision_device_bulk(request.serial_number)

            self._logger.info("Successfully unprovisioned device %s", request.serial_number)
            return UnprovisioningResult(
                status=ProvisioningStatus.SUCCESS,
                serial_number=request.serial_number,
            )
        except Exception as e:
            self._logger.error("Unprovisioning failed for device %s: %s", request.serial_number, str(e))
            return UnprovisioningResult(
                status=ProvisioningStatus.FAILED,
                serial_number=request.serial_number,
                error_message=str(e),
            )

    def get_certificate(self, request: CertificateRequest) -> CertificateResult:
        """Retrieve the agent configuration file for an already-provisioned device.

        Fetches the ConnHex ID from PMS and the init key from the IoT API, then
        writes the agent.env config file to disk. The file content is stable —
        it will not change between calls unless the device is unprovisioned and
        reprovisioned.

        Args:
            request: Certificate request containing the device serial number and
                output path for the configuration file.

        Returns:
            CertificateResult with status SUCCESS and the written config file path,
            or status FAILED with an error message on any failure.

        Note:
            Failures are not raised (DeviceNotFoundError, CertificateRetrievalError, ConfigurationError); they are
            returned as status FAILED with the cause in ``error_message``.
        """
        self._logger.info("Starting certificate retrieval for device %s", request.serial_number)
        try:
            connhex_id = self._get_device_connhex_id(request.serial_number)
            init_key = self._get_device_init_key(connhex_id)
            config_file_path = self._create_config_file(request.serial_number, init_key, request.config_output_path)

            self._logger.info("Successfully retrieved certificate for device %s", request.serial_number)
            return CertificateResult(
                status=ProvisioningStatus.SUCCESS,
                serial_number=request.serial_number,
                connhex_id=connhex_id,
                config_file_path=config_file_path,
            )
        except Exception as e:
            self._logger.error("Certificate retrieval failed for device %s: %s", request.serial_number, str(e))
            return CertificateResult(
                status=ProvisioningStatus.FAILED,
                serial_number=request.serial_number,
                error_message=str(e),
            )

    # --- private helpers ---

    def _get_tenant_id(self, customer_code: str) -> str:
        self._logger.debug("Looking up customer with code: %s", customer_code)
        try:
            customer = self._pms_client.customer.get("code", customer_code)
        except Exception as e:
            raise CustomerNotFoundError(f"Error retrieving customer {customer_code}: {e}") from e
        if not customer or not getattr(customer, "tenant_id", None):
            raise CustomerNotFoundError(f"No tenant ID found for customer: {customer_code}")
        return cast(str, customer.tenant_id)

    def _provision_device_bulk(self, serial_number: str, tenant_id: str, manufacturing_data: Dict[str, Any]) -> None:
        self._logger.debug("Provisioning device %s with tenant %s", serial_number, tenant_id)
        payload = {
            "devices": [{"serial": serial_number, "tenant": tenant_id, "manufacturing": manufacturing_data}],
        }
        try:
            self._tolomeo_client.post("devices/provision/bulk", json=payload)
        except Exception as e:
            raise DeviceProvisioningError(f"Failed to provision device {serial_number}: {e}") from e

    def _unprovision_device_bulk(self, serial_number: str) -> None:
        self._logger.debug("Unprovisioning device %s", serial_number)
        try:
            self._tolomeo_client.delete("devices/provision/bulk", json={"serials": [serial_number]})
        except Exception as e:
            raise UnprovisioningError(f"Failed to unprovision device {serial_number}: {e}") from e

    def _get_device_connhex_id(self, serial_number: str) -> str:
        self._logger.debug("Retrieving device info for %s", serial_number)
        try:
            device = self._pms_client.device.get("serial_number", serial_number)
        except Exception as e:
            raise DeviceNotFoundError(f"Error retrieving device {serial_number}: {e}") from e
        if not device:
            raise DeviceNotFoundError(f"Device {serial_number} not found in manufacturing")
        if not getattr(device, "connhex_id", None):
            raise DeviceNotFoundError(f"No connhex_id found for device {serial_number}")
        return cast(str, device.connhex_id)

    def _get_device_init_key(self, connhex_id: str) -> SecretStr:
        self._logger.debug("Retrieving thing for connhex_id: %s", connhex_id)
        try:
            data = self._iot_client.get(f"things/{connhex_id}").json()
        except Exception as e:
            raise CertificateRetrievalError(f"Failed to get thing for {connhex_id}: {e}") from e
        init_key_value = data.get("metadata", {}).get("init_key") if isinstance(data, dict) else None
        if not init_key_value:
            raise CertificateRetrievalError(f"No init_key found in IoT response for {connhex_id}")
        return SecretStr(init_key_value)

    def _create_config_file(self, serial_number: str, init_key: SecretStr, output_path: Path) -> Path:
        try:
            config_content = self.CONFIG_TEMPLATE.format(
                serial_number=serial_number,
                init_key=init_key.get_secret_value(),
                instance=self._instance,
            )
            output_path.parent.mkdir(parents=True, exist_ok=True)
            output_path.write_text(config_content)
            return output_path
        except Exception as e:
            raise ConfigurationError(f"Failed to create configuration file {output_path}: {e}") from e

get_certificate(request)

Retrieve the agent configuration file for an already-provisioned device.

Fetches the ConnHex ID from PMS and the init key from the IoT API, then writes the agent.env config file to disk. The file content is stable — it will not change between calls unless the device is unprovisioned and reprovisioned.

Parameters:

Name Type Description Default
request CertificateRequest

Certificate request containing the device serial number and output path for the configuration file.

required

Returns:

Type Description
CertificateResult

CertificateResult with status SUCCESS and the written config file path,

CertificateResult

or status FAILED with an error message on any failure.

Note

Failures are not raised (DeviceNotFoundError, CertificateRetrievalError, ConfigurationError); they are returned as status FAILED with the cause in error_message.

Source code in tlm_cli/manufacturing/provisioning/device.py
def get_certificate(self, request: CertificateRequest) -> CertificateResult:
    """Retrieve the agent configuration file for an already-provisioned device.

    Fetches the ConnHex ID from PMS and the init key from the IoT API, then
    writes the agent.env config file to disk. The file content is stable —
    it will not change between calls unless the device is unprovisioned and
    reprovisioned.

    Args:
        request: Certificate request containing the device serial number and
            output path for the configuration file.

    Returns:
        CertificateResult with status SUCCESS and the written config file path,
        or status FAILED with an error message on any failure.

    Note:
        Failures are not raised (DeviceNotFoundError, CertificateRetrievalError, ConfigurationError); they are
        returned as status FAILED with the cause in ``error_message``.
    """
    self._logger.info("Starting certificate retrieval for device %s", request.serial_number)
    try:
        connhex_id = self._get_device_connhex_id(request.serial_number)
        init_key = self._get_device_init_key(connhex_id)
        config_file_path = self._create_config_file(request.serial_number, init_key, request.config_output_path)

        self._logger.info("Successfully retrieved certificate for device %s", request.serial_number)
        return CertificateResult(
            status=ProvisioningStatus.SUCCESS,
            serial_number=request.serial_number,
            connhex_id=connhex_id,
            config_file_path=config_file_path,
        )
    except Exception as e:
        self._logger.error("Certificate retrieval failed for device %s: %s", request.serial_number, str(e))
        return CertificateResult(
            status=ProvisioningStatus.FAILED,
            serial_number=request.serial_number,
            error_message=str(e),
        )

provision(request)

Provision a device and write its agent configuration file.

Executes the full provisioning sequence: verifies the device does not already exist, resolves the customer tenant ID, calls the bulk provisioning API, fetches the ConnHex ID from PMS, retrieves the init key from the IoT API, and writes the agent.env config file to disk.

Parameters:

Name Type Description Default
request ProvisioningRequest

Provisioning request containing serial number, customer code, and output path for the configuration file.

required

Returns:

Type Description
ProvisioningResult

ProvisioningResult with status SUCCESS and the written config file path,

ProvisioningResult

or status FAILED with an error message on any failure.

Note

Failures are not raised (DeviceAlreadyExistsError, CustomerNotFoundError, DeviceProvisioningError, CertificateRetrievalError, ConfigurationError); they are returned as status FAILED with the cause in error_message.

Source code in tlm_cli/manufacturing/provisioning/device.py
def provision(self, request: ProvisioningRequest) -> ProvisioningResult:
    """Provision a device and write its agent configuration file.

    Executes the full provisioning sequence: verifies the device does not
    already exist, resolves the customer tenant ID, calls the bulk provisioning
    API, fetches the ConnHex ID from PMS, retrieves the init key from the IoT
    API, and writes the agent.env config file to disk.

    Args:
        request: Provisioning request containing serial number, customer code,
            and output path for the configuration file.

    Returns:
        ProvisioningResult with status SUCCESS and the written config file path,
        or status FAILED with an error message on any failure.

    Note:
        Failures are not raised (DeviceAlreadyExistsError, CustomerNotFoundError, DeviceProvisioningError,
        CertificateRetrievalError, ConfigurationError); they are returned as status FAILED with the cause in
        ``error_message``.
    """
    self._logger.info("Starting provisioning for device %s", request.serial_number)
    try:
        if self._pms_client.device.exists("serial_number", request.serial_number):
            raise DeviceAlreadyExistsError(f"Device {request.serial_number} already exists in manufacturing")

        tenant_id = self._get_tenant_id(request.customer_code)
        self._provision_device_bulk(request.serial_number, tenant_id, request.manufacturing_data)
        connhex_id = self._get_device_connhex_id(request.serial_number)
        init_key = self._get_device_init_key(connhex_id)
        config_file_path = self._create_config_file(request.serial_number, init_key, request.config_output_path)

        self._logger.info("Successfully provisioned device %s", request.serial_number)
        return ProvisioningResult(
            status=ProvisioningStatus.SUCCESS,
            serial_number=request.serial_number,
            connhex_id=connhex_id,
            config_file_path=config_file_path,
            tenant_id=tenant_id,
        )
    except Exception as e:
        self._logger.error("Provisioning failed for device %s: %s", request.serial_number, str(e))
        return ProvisioningResult(
            status=ProvisioningStatus.FAILED,
            serial_number=request.serial_number,
            error_message=str(e),
        )

unprovision(request)

Permanently remove all provisioning records for a device via the bulk API.

Parameters:

Name Type Description Default
request UnprovisioningRequest

Unprovisioning request containing the device serial number.

required

Returns:

Type Description
UnprovisioningResult

UnprovisioningResult with status SUCCESS, or status FAILED with an

UnprovisioningResult

error message on any failure.

Note

Failures are not raised (DeviceNotFoundError, UnprovisioningError); they are returned as status FAILED with the cause in error_message.

Source code in tlm_cli/manufacturing/provisioning/device.py
def unprovision(self, request: UnprovisioningRequest) -> UnprovisioningResult:
    """Permanently remove all provisioning records for a device via the bulk API.

    Args:
        request: Unprovisioning request containing the device serial number.

    Returns:
        UnprovisioningResult with status SUCCESS, or status FAILED with an
        error message on any failure.

    Note:
        Failures are not raised (DeviceNotFoundError, UnprovisioningError); they are returned as status FAILED with
        the cause in ``error_message``.
    """
    self._logger.info("Starting unprovisioning for device %s", request.serial_number)
    try:
        if not self._pms_client.device.exists("serial_number", request.serial_number):
            raise DeviceNotFoundError(f"Device {request.serial_number} not found in manufacturing")

        self._unprovision_device_bulk(request.serial_number)

        self._logger.info("Successfully unprovisioned device %s", request.serial_number)
        return UnprovisioningResult(
            status=ProvisioningStatus.SUCCESS,
            serial_number=request.serial_number,
        )
    except Exception as e:
        self._logger.error("Unprovisioning failed for device %s: %s", request.serial_number, str(e))
        return UnprovisioningResult(
            status=ProvisioningStatus.FAILED,
            serial_number=request.serial_number,
            error_message=str(e),
        )

Request models

tlm_cli.manufacturing.provisioning.models.ProvisioningRequest

Bases: DeviceRequestBase

Request model for provisioning a device.

Contains all necessary information for provisioning, including customer details, configuration output, and optional manufacturing data.

Attributes:

Name Type Description
serial_number str

Device serial number (inherited).

customer_code str

Customer code for tenant identification.

config_output_path Path

Path where the configuration file will be created.

manufacturing_data Dict

Optional manufacturing metadata.

Examples:

Basic request:

>>> ProvisioningRequest(serial_number="DEV123", customer_code="ACME")

Custom config path:

>>> ProvisioningRequest(
...     serial_number="DEV123",
...     customer_code="ACME",
...     config_output_path=Path("/opt/configs/device.env")
... )

With manufacturing data:

>>> ProvisioningRequest(
...     serial_number="DEV123",
...     customer_code="ACME",
...     manufacturing_data={"batch": "B001", "revision": "v2.1"}
... )
Source code in tlm_cli/manufacturing/provisioning/models.py
class ProvisioningRequest(DeviceRequestBase):
    """Request model for provisioning a device.

    Contains all necessary information for provisioning, including
    customer details, configuration output, and optional manufacturing data.

    Attributes:
        serial_number (str): Device serial number (inherited).
        customer_code (str): Customer code for tenant identification.
        config_output_path (Path): Path where the configuration file will be created.
        manufacturing_data (Dict): Optional manufacturing metadata.

    Examples:
        Basic request:
        >>> ProvisioningRequest(serial_number="DEV123", customer_code="ACME")

        Custom config path:
        >>> ProvisioningRequest(
        ...     serial_number="DEV123",
        ...     customer_code="ACME",
        ...     config_output_path=Path("/opt/configs/device.env")
        ... )

        With manufacturing data:
        >>> ProvisioningRequest(
        ...     serial_number="DEV123",
        ...     customer_code="ACME",
        ...     manufacturing_data={"batch": "B001", "revision": "v2.1"}
        ... )
    """

    customer_code: str = Field(..., min_length=1)
    config_output_path: Path = Field(default_factory=lambda: Path(DEFAULT_AGENT_FILENAME))
    manufacturing_data: Dict = Field(default_factory=dict)

tlm_cli.manufacturing.provisioning.models.UnprovisioningRequest

Bases: DeviceRequestBase

Request model for unprovisioning a device.

Currently only requires a serial number, but designed to be extensible for future use.

Attributes:

Name Type Description
serial_number str

Device serial number (inherited).

Examples:

>>> req = UnprovisioningRequest(serial_number="DEV123")
>>> print(req.serial_number)
DEV123
Source code in tlm_cli/manufacturing/provisioning/models.py
class UnprovisioningRequest(DeviceRequestBase):
    """Request model for unprovisioning a device.

    Currently only requires a serial number, but designed to be
    extensible for future use.

    Attributes:
        serial_number (str): Device serial number (inherited).

    Examples:
        >>> req = UnprovisioningRequest(serial_number="DEV123")
        >>> print(req.serial_number)
        DEV123
    """

    pass

tlm_cli.manufacturing.provisioning.models.CertificateRequest

Bases: DeviceRequestBase

Request model for retrieving the agent configuration of an already-provisioned device.

Attributes:

Name Type Description
serial_number str

Device serial number (inherited).

config_output_path Path

Path where the configuration file will be written. Defaults to agent.env in the current directory.

Examples:

>>> CertificateRequest(serial_number="DEV123")
>>> CertificateRequest(serial_number="DEV123", config_output_path=Path("/opt/configs/agent.env"))
Source code in tlm_cli/manufacturing/provisioning/models.py
class CertificateRequest(DeviceRequestBase):
    """Request model for retrieving the agent configuration of an already-provisioned device.

    Attributes:
        serial_number (str): Device serial number (inherited).
        config_output_path (Path): Path where the configuration file will be written.
            Defaults to ``agent.env`` in the current directory.

    Examples:
        >>> CertificateRequest(serial_number="DEV123")
        >>> CertificateRequest(serial_number="DEV123", config_output_path=Path("/opt/configs/agent.env"))
    """

    config_output_path: Path = Field(default_factory=lambda: Path(DEFAULT_AGENT_FILENAME))

Result models

tlm_cli.manufacturing.provisioning.models.ProvisioningResult

Bases: ResultBase

Result model for device provisioning operations.

Contains all information returned from a successful or failed provisioning operation, including device identifiers and configuration.

Attributes:

Name Type Description
status ProvisioningStatus

Operation status (inherited).

serial_number str

Device serial number (inherited).

error_message Optional[str]

Error description (inherited).

connhex_id Optional[str]

ConnHex ID assigned (on success).

config_file_path Optional[Path]

Path to configuration file (on success).

tenant_id Optional[str]

Tenant ID used for provisioning (on success).

Examples:

Successful result:

>>> ProvisioningResult(
...     status=ProvisioningStatus.SUCCESS,
...     serial_number="DEV123",
...     connhex_id="cx-12345",
...     config_file_path=Path("agent.env"),
...     tenant_id="tenant-456"
... )

Failed result:

>>> ProvisioningResult(
...     status=ProvisioningStatus.FAILED,
...     serial_number="DEV123",
...     error_message="Customer not found"
... )
Source code in tlm_cli/manufacturing/provisioning/models.py
class ProvisioningResult(ResultBase):
    """Result model for device provisioning operations.

    Contains all information returned from a successful or failed
    provisioning operation, including device identifiers and configuration.

    Attributes:
        status (ProvisioningStatus): Operation status (inherited).
        serial_number (str): Device serial number (inherited).
        error_message (Optional[str]): Error description (inherited).
        connhex_id (Optional[str]): ConnHex ID assigned (on success).
        config_file_path (Optional[Path]): Path to configuration file (on success).
        tenant_id (Optional[str]): Tenant ID used for provisioning (on success).

    Examples:
        Successful result:
        >>> ProvisioningResult(
        ...     status=ProvisioningStatus.SUCCESS,
        ...     serial_number="DEV123",
        ...     connhex_id="cx-12345",
        ...     config_file_path=Path("agent.env"),
        ...     tenant_id="tenant-456"
        ... )

        Failed result:
        >>> ProvisioningResult(
        ...     status=ProvisioningStatus.FAILED,
        ...     serial_number="DEV123",
        ...     error_message="Customer not found"
        ... )
    """

    connhex_id: str | None = None
    config_file_path: Path | None = None
    tenant_id: str | None = None

tlm_cli.manufacturing.provisioning.models.UnprovisioningResult

Bases: ResultBase

Result model for device unprovisioning operations.

Contains information returned from a successful or failed unprovisioning operation.

Attributes:

Name Type Description
status ProvisioningStatus

Operation status (inherited).

serial_number str

Device serial number (inherited).

error_message Optional[str]

Error description (inherited).

Examples:

Successful result:

>>> UnprovisioningResult(
...     status=ProvisioningStatus.SUCCESS,
...     serial_number="DEV123"
... )

Failed result:

>>> UnprovisioningResult(
...     status=ProvisioningStatus.FAILED,
...     serial_number="DEV123",
...     error_message="Device not found"
... )
Source code in tlm_cli/manufacturing/provisioning/models.py
class UnprovisioningResult(ResultBase):
    """Result model for device unprovisioning operations.

    Contains information returned from a successful or failed
    unprovisioning operation.

    Attributes:
        status (ProvisioningStatus): Operation status (inherited).
        serial_number (str): Device serial number (inherited).
        error_message (Optional[str]): Error description (inherited).

    Examples:
        Successful result:
        >>> UnprovisioningResult(
        ...     status=ProvisioningStatus.SUCCESS,
        ...     serial_number="DEV123"
        ... )

        Failed result:
        >>> UnprovisioningResult(
        ...     status=ProvisioningStatus.FAILED,
        ...     serial_number="DEV123",
        ...     error_message="Device not found"
        ... )
    """

    pass

tlm_cli.manufacturing.provisioning.models.CertificateResult

Bases: ResultBase

Result model for certificate/configuration retrieval operations.

Contains information returned from a successful or failed certificate retrieval operation for existing devices.

Attributes:

Name Type Description
status ProvisioningStatus

Operation status (inherited).

serial_number str

Device serial number (inherited).

error_message Optional[str]

Error description (inherited).

connhex_id Optional[str]

ConnHex ID retrieved (on success).

config_file_path Optional[Path]

Path to configuration file (on success).

Examples:

Successful result:

>>> CertificateResult(
...     status=ProvisioningStatus.SUCCESS,
...     serial_number="DEV123",
...     connhex_id="cx-12345",
...     config_file_path=Path("agent.env")
... )

Failed result:

>>> CertificateResult(
...     status=ProvisioningStatus.FAILED,
...     serial_number="DEV123",
...     error_message="Device not found in manufacturing"
... )
Source code in tlm_cli/manufacturing/provisioning/models.py
class CertificateResult(ResultBase):
    """Result model for certificate/configuration retrieval operations.

    Contains information returned from a successful or failed
    certificate retrieval operation for existing devices.

    Attributes:
        status (ProvisioningStatus): Operation status (inherited).
        serial_number (str): Device serial number (inherited).
        error_message (Optional[str]): Error description (inherited).
        connhex_id (Optional[str]): ConnHex ID retrieved (on success).
        config_file_path (Optional[Path]): Path to configuration file (on success).

    Examples:
        Successful result:
        >>> CertificateResult(
        ...     status=ProvisioningStatus.SUCCESS,
        ...     serial_number="DEV123",
        ...     connhex_id="cx-12345",
        ...     config_file_path=Path("agent.env")
        ... )

        Failed result:
        >>> CertificateResult(
        ...     status=ProvisioningStatus.FAILED,
        ...     serial_number="DEV123",
        ...     error_message="Device not found in manufacturing"
        ... )
    """

    connhex_id: str | None = None
    config_file_path: Path | None = None

tlm_cli.manufacturing.provisioning.models.ProvisioningStatus

Bases: StrEnum

Enumeration of provisioning operation statuses.

Defines standardized outcomes for provisioning and unprovisioning operations.

Attributes:

Name Type Description
SUCCESS str

Operation completed successfully.

FAILED str

Operation failed due to an error.

Examples:

>>> status = ProvisioningStatus.SUCCESS
>>> print(status.value)
success
>>> if status is ProvisioningStatus.SUCCESS:
...     print("Operation succeeded")
Source code in tlm_cli/manufacturing/provisioning/models.py
class ProvisioningStatus(StrEnum):
    """Enumeration of provisioning operation statuses.

    Defines standardized outcomes for provisioning and unprovisioning
    operations.

    Attributes:
        SUCCESS (str): Operation completed successfully.
        FAILED (str): Operation failed due to an error.

    Examples:
        >>> status = ProvisioningStatus.SUCCESS
        >>> print(status.value)
        success
        >>> if status is ProvisioningStatus.SUCCESS:
        ...     print("Operation succeeded")
    """

    SUCCESS = "success"
    FAILED = "failed"

Exceptions

tlm_cli.manufacturing.provisioning.exceptions.ProvisioningError

Bases: Exception

Base exception for all provisioning-related errors.

This is the parent class for all provisioning exceptions, allowing callers to catch all provisioning-related errors with a single handler if desired.

Examples:

>>> try:
...     provisioner.provision(request)
... except ProvisioningError as e:
...     print(f"Provisioning failed: {e}")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class ProvisioningError(Exception):
    """Base exception for all provisioning-related errors.

    This is the parent class for all provisioning exceptions, allowing
    callers to catch all provisioning-related errors with a single
    handler if desired.

    Examples:
        >>> try:
        ...     provisioner.provision(request)
        ... except ProvisioningError as e:
        ...     print(f"Provisioning failed: {e}")
    """

tlm_cli.manufacturing.provisioning.exceptions.CustomerNotFoundError

Bases: ProvisioningError

Exception raised when a customer record is missing or invalid.

This error occurs in cases such as
  • The customer code does not exist in the PMS system.
  • The customer exists but has no associated tenant ID.
  • Retrieving customer information from the API fails.

Examples:

>>> raise CustomerNotFoundError("Customer 'INVALID' not found")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class CustomerNotFoundError(ProvisioningError):
    """Exception raised when a customer record is missing or invalid.

    This error occurs in cases such as:
      * The customer code does not exist in the PMS system.
      * The customer exists but has no associated tenant ID.
      * Retrieving customer information from the API fails.

    Examples:
        >>> raise CustomerNotFoundError("Customer 'INVALID' not found")
    """

tlm_cli.manufacturing.provisioning.exceptions.DeviceProvisioningError

Bases: ProvisioningError

Exception raised when device provisioning or unprovisioning fails.

This error occurs in cases such as
  • The bulk provisioning API returns an error.
  • The bulk unprovisioning API returns an error.
  • Network or communication errors occur during API calls.

Examples:

>>> raise DeviceProvisioningError("Failed to provision device DEV123")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class DeviceProvisioningError(ProvisioningError):
    """Exception raised when device provisioning or unprovisioning fails.

    This error occurs in cases such as:
      * The bulk provisioning API returns an error.
      * The bulk unprovisioning API returns an error.
      * Network or communication errors occur during API calls.

    Examples:
        >>> raise DeviceProvisioningError("Failed to provision device DEV123")
    """

tlm_cli.manufacturing.provisioning.exceptions.DeviceAlreadyExistsError

Bases: DeviceProvisioningError

Exception raised when attempting to provision a device that already exists.

This is a specific case of DeviceProvisioningError that occurs when a device serial number already exists in the manufacturing system during provisioning attempts.

Examples:

>>> raise DeviceAlreadyExistsError("Device DEV123 already exists in manufacturing")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class DeviceAlreadyExistsError(DeviceProvisioningError):
    """Exception raised when attempting to provision a device that already exists.

    This is a specific case of DeviceProvisioningError that occurs when
    a device serial number already exists in the manufacturing system
    during provisioning attempts.

    Examples:
        >>> raise DeviceAlreadyExistsError("Device DEV123 already exists in manufacturing")
    """

tlm_cli.manufacturing.provisioning.exceptions.DeviceNotFoundError

Bases: ProvisioningError

Exception raised when a device cannot be found in the PMS system.

This error occurs in cases such as
  • A device serial number does not exist in manufacturing.
  • A device exists but has no associated ConnHex ID.
  • Retrieving device information from the API fails.

Examples:

>>> raise DeviceNotFoundError("Device 'DEV123' not found in manufacturing")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class DeviceNotFoundError(ProvisioningError):
    """Exception raised when a device cannot be found in the PMS system.

    This error occurs in cases such as:
      * A device serial number does not exist in manufacturing.
      * A device exists but has no associated ConnHex ID.
      * Retrieving device information from the API fails.

    Examples:
        >>> raise DeviceNotFoundError("Device 'DEV123' not found in manufacturing")
    """

tlm_cli.manufacturing.provisioning.exceptions.ConfigurationError

Bases: ProvisioningError

Exception raised when device configuration operations fail.

This error occurs in cases such as
  • The configuration API returns an error.
  • The API response contains no payload or invalid data.
  • The initialization key is missing from the response.
  • Configuration file creation fails.

Examples:

>>> raise ConfigurationError("No init_key found in response")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class ConfigurationError(ProvisioningError):
    """Exception raised when device configuration operations fail.

    This error occurs in cases such as:
      * The configuration API returns an error.
      * The API response contains no payload or invalid data.
      * The initialization key is missing from the response.
      * Configuration file creation fails.

    Examples:
        >>> raise ConfigurationError("No init_key found in response")
    """

tlm_cli.manufacturing.provisioning.exceptions.CertificateRetrievalError

Bases: ConfigurationError

Exception raised when certificate/configuration retrieval fails.

This is a specific case of ConfigurationError that occurs during certificate retrieval operations for existing devices.

Examples:

>>> raise CertificateRetrievalError("Failed to retrieve certificate for device DEV123")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class CertificateRetrievalError(ConfigurationError):
    """Exception raised when certificate/configuration retrieval fails.

    This is a specific case of ConfigurationError that occurs during
    certificate retrieval operations for existing devices.

    Examples:
        >>> raise CertificateRetrievalError("Failed to retrieve certificate for device DEV123")
    """

tlm_cli.manufacturing.provisioning.exceptions.UnprovisioningError

Bases: DeviceProvisioningError

Exception raised when device unprovisioning operations fail.

This is a specific case of DeviceProvisioningError that occurs during device removal from the manufacturing system.

Examples:

>>> raise UnprovisioningError("Failed to unprovision device DEV123")
Source code in tlm_cli/manufacturing/provisioning/exceptions.py
class UnprovisioningError(DeviceProvisioningError):
    """Exception raised when device unprovisioning operations fail.

    This is a specific case of DeviceProvisioningError that occurs during
    device removal from the manufacturing system.

    Examples:
        >>> raise UnprovisioningError("Failed to unprovision device DEV123")
    """