- iDigi Dia Home
- User
  - Getting Started
  - Dia Concepts
  - Devices
  - Loggers
  - Presentations
  - Services
  - Tracing
- Developer
  - Overview
  - Drivers
  - Loggers
  - Presentations
  - Services
  - Integrating Application
  - Tracing Manager
  - Debugging
  - Specific Considerations
  - API Reference

- Email
- Phone
- Contact us:

### Navigation

- index
- next |
- previous |
- iDigi Dia |
- User Documentation »
- Device Drivers »

# Transforms Device

## Overview

The transforms device, as the name implies, provides a means to transform the content of channels. Given a list of channels, a new channel is created that is the result of a simple expression on the input channels.

There are many possible uses for this type of functionality unit conversion, input validation, creating terms that drive further logic, filtering and more.

## Configuration

A typical transforms configuration block looks like this:

    - name: template_transforms
      driver: devices.transforms_device:TransformsDevice
      settings:
        - name: count_by_two
          channels:
            - template.counter
          expr: c[0] * 2

### Settings

The settings for the transforms device are a list of individual transform specification blocks. Each item in the list has the following items.

name (required)
  The channel name that will be created by this transform. The full name is the name of the driver instance declaration a period and the name of the individual transform. ex. `template.transforms.count_by_two` in the example given above.
channels (required)
  A list of channels from the channel database that will be the inputs to the `expr` item.
expr (required)

  A single Python expression. The value of the expression will be the value of the channel that is created. This expression will be evaluated every time one of the channels listed by the `channels` item is published to the channel database.

  The expression may make use of Python built-in functions to compute its value. The values from the `channels` list are provided to the expression in a list `c`. The order of elements of `c` are retained in the order listed in the configuration file.

### How the expression works

The expression is evaluated with the python function call “eval”. Eval works by taking a string representing a valid python statement, with a dictionary as input, and returning the result of that statement. Using the code snippet presented above, the command looks like:

eval(“c[0] * 2”, {c: [template.counter]})

The output of the statement will produce a value that is twice the value of the input, template.counter.

### How to test the expression

The expression can be tested in a test environment without using the Dia. To test this, the user can use a python interpreter session to perform the same evaluations:

    def my_eval(s, inputs):
     d = {"c":[x for x in inputs]}
     return eval(s, d)

    print my_eval("c[0] + 123", [1])

The above is the equivalent to the following yaml:

    - name: transforms
      driver: devices.transforms_device:TransformsDevice
      settings:
        - name: add_123
          channels:
            - template.counter
          expr: c[0] + 123

When the input template.counter is equal to integer 1.

Another example:

    print my_eval("c[0] * 1.8 + 32", [50])

This would be the equivalent to the following yaml:

    - name: transforms
      driver: devices.transforms_device:TransformsDevice
      settings:
        - name: C_to_F
          channels:
            - input.celsius
          expr: c[0] + * 1.8 + 32

### Advanced logic examples:

Because the eval() python function is used, more complicated, compound statements can be made. For instance, a branching statement can be used:

    "c[0] > 10 and c[0] or "Not valid""

The above compares the input to integer 10, and if greater than uses the input value, otherwise substitutes 0. If the input was 15, the output is 15, if the input 7, then the output is “Not valid”.

This behavior can be useful if the user wants to filter the input based on a measurable condition, and give either the value, or some identifiable error condition:

    "c[0] == True and 'Conditional is True' or 'Conditional is False'"

The above evaluates if the input is equal to True, and sets the output to “Conditional is True”. If the comparison is False, it returns “Conditional is False”.

### Multiple input examples:

In some circumstances the user wants to create a transform that has multiple inputs to create a single output. Each input is assigned an index of c, so for example, the following yaml:

    - name: transforms
      driver: devices.transforms_device:TransformsDevice
      settings:
        - name: add_vals
          channels:
            - input.val1
            - input.val2
          expr: c[0] + c[1]

The above adds the two inputs together, with input.val1 being represented by c[0] and input.val2 being represented by c[1]. Additional inputs would be represented by c[2], c[3], etc. in the order they are defined in the channels setting.

### Multiple transforms in a driver:

Multiple transforms can be used in a single driver:

    - name: transforms
      driver: devices.transforms_device:TransformsDevice
      settings:
        - name: double
          channels:
            - template.counter
          expr: c[0] * 2

        - name: triple
          channels:
            - template.counter
          expr: c[0] * 3

The above yaml defines two output channels for the Transform device.

### Creating chains of transforms:

In some circumstances, its necessary to chain together transforms to aggregate data, or produce a summary or status line of the current system. Transform drivers are flexible, and can be used to reference other channels produced by the same driver:

    - name: t1
      driver: devices.transforms_device:TransformsDevice
      settings:
        - name: double
          channels:
            - template.counter
          expr: c[0] * 2

        - name: double_double
          channels:
            - t1.double
          expr: c[0] * 2

The above demonstrates a transform that doubles templace.counter, and will then in turn double that output, resulting in a value that is 4 times template.counter in the channel t1.double_double.

A more useful transform driver could aggregate the information, for use in a presentation that pushes data, like the TCPCSV presentation:

    - name: t1
      driver: devices.transforms_device:TransformsDevice
      settings:
        - name: double
          channels:
            - template.counter
          expr: c[0] * 2

        - name: triple
          channels:
            - template.counter
          expr: c[0] * 3

        - name: csv_out
          channels:
            - t1.double
            - t1.triple
          expr: "','.join(str(x) for x in  c)"

The above shows how to comma separate the input channels into a single output channel that can be easily extended to include other inputs.

Note

When using quotes in the expression, make sure to use single quotes, and surround them with double quotes in the yaml.

### Navigation

- index
- next |
- previous |
- iDigi Dia |
- User Documentation »
- Device Drivers »