How to configure ODS

A basic json

The configuration example uses the following JSON for a simple configuration. This configuration expects at least one Head (3D imager) at port 2.

{
    "applications": {
      "instances": {
        "app0": {
          "class": "ods",
          "name":"app0",
          "ports": [
            "port2",
            "port6"
          ],
          "state": "CONF"
        }
      }
    }
  }

Note

port6 is always part of the “ports” configuration. It refers to the IMU and is needed for the ODS algorithm to work properly.

The configuration example

#############################################
# Copyright 2021-present ifm electronic, gmbh
# SPDX-License-Identifier: Apache-2.0
#############################################

import json
import logging
import pathlib
from jsonschema import exceptions as json_exceptions
from jsonschema import validate
from ifm3dpy.device import Error as ifm3dpy_error
from ifm3dpy.device import O3R


class ODSConfig:
    """Provides functions showcasing how to handle json configuration
    of an O3R device, using the ifm3dpy library.
    """

    def __init__(self, o3r: O3R) -> None:
        self.o3r = o3r
        self.schema = o3r.get_schema()
        self.logger = logging.getLogger(__name__)
        logging.basicConfig(
            format="%(asctime)s:%(filename)-10s:%(levelname)-8s:%(message)s",
            datefmt="%y-%m-%d %H:%M:%S",
        )
        self.logger.setLevel(logging.DEBUG)

    def validate_json(self, config: json) -> bool:
        """This function can be used to validate
        a configuration before setting it.
        Note that ifm3dpy.device.O3R.set() will validate the
        requested configuration, but using the jsonschema.validate
        function will provide a more verbose validation.

        :param config: the configuration to validate
        :raises ValidationError: if the validation fails
        """
        try:
            self.logger.info(f"Validating configuration")
            validate(config, self.schema)
        except json_exceptions.ValidationError as err:
            self.logger.exception("Error while validating the json schema")
            raise err
        except json_exceptions.SchemaError as err:
            self.logger.exception("Incorrect json schema")
            raise err

    def set_config_from_file(self, config_file: pathlib.Path):
        """Configure the device from a configuration file.
        The provided configuration is validated using the schema validator.

        :param config_file: path to the configuration file
        """
        try:
            self.logger.info(f"Loading configuration from file {config_file}")
            with open(config_file, "r") as f:
                config = json.load(f)
            # This function will validate the configuration against the schema
            # and apply it to the O3R.
            self.set_config_from_dict(config)
        except OSError as err:
            self.logger.exception("Error while reading configuration file")
            raise err

    def set_config_from_dict(self, config: json):
        """Configure the device provided a configuration dictionary.
        The provided configuration is validated using the schema validator.

        :param config: dictionary of the desired configuration
        :raises ifm3dpy.device.Error: if the configuration fails
        """
        try:
            self.validate_json(config)
            self.logger.info(f"Setting configuration {config}")
            self.o3r.set(config)
        except ifm3dpy_error as err:
            self.logger.exception("Error while configurating device")
            raise err

    def get(self, config_path=[""]):
        """Get current configuration fragment, provided the expected dictionary.
        If nothing is provided, the full configuration will be returned.
        Note that this function can be used exactly as the ifm3dpy.device.O3R.get() function
        :param config_path: fragment of configuration to retrieve
        :return: the configuration
        :raises ifm3dpy.device.Error: if the configuration cannot be retrieved
        """
        try:
            self.logger.info(f"Getting configuration at {config_path}")
            return self.o3r.get(config_path)
        except ifm3dpy_error as err:
            self.logger.exception("Error while getting configuration")
            raise err


def main():
    """
    Example on how to use the ODSConfig class.
    Make sure you configure the IP address for your specific setup.
    """
    IP = "192.168.0.69"
    o3r = O3R(IP)
    ods_config = ODSConfig(o3r=o3r)
    #############################################
    # Examples on getting configurations snippets
    #############################################
    ods_config.logger.info(ods_config.get())  # Get the full configuration
    ods_config.logger.info(
        ods_config.get(
            ["/device/swVersion/firmware"]
        )  # Get a subset of the configuration
    )
    ods_config.logger.info(
        ods_config.get(
            ["/device/swVersion/firmware", "/device/status", "/ports/port0/info"]
        )  # Get multiple fragments of the configuration
    )
    try:  # This will throw an exception
        ods_config.logger.info(ods_config.get(["/device/wrongkey"]))
    # Failing silently to continue through the examples
    except ifm3dpy_error:
        pass
    #####################################
    # Examples on setting configurations
    #####################################
    ods_config.set_config_from_dict(
        {"device": {"info": {"description": "I will use this O3R to change the world"}}}
    )
    ods_config.set_config_from_dict(  # Set two configuration fragments at the same time
        {
            "device": {"info": {"name": "my_favorite_o3r"}},
            "ports": {"port0": {"info": {"name": "my_favorite_port"}}},
        }  # Assume port connected in port0
    )
    try:  # This will throw an exception
        ods_config.set_config_from_dict({"device": {"info": {"description": 0}}})
    # Failing silently to continue through the examples
    except json_exceptions.ValidationError:
        pass

    ods_config.set_config_from_file("configs/ods_one_head_config.json")
    try:  # This will throw an exception
        ods_config.set_config_from_file("non/existent/file.json")
    # Failing silently to continue through the examples
    except OSError:
        pass

    ods_config.logger.info("You reached the end of the ODSConfig tutorial!")


if __name__ == "__main__":
    main()

Tip

Resetting the application(s) If issues with the receiving of data or changing the configuration occur, an reset of the application(s) could solve these issues.

from ifm3dpy.device import O3R
o3r = O3R()
o3r.reset("/applications")