# Attributes
Attributes are a way to specify some additional meta-data to your information model objects. Without attributes, when you define some properties or variables, you can provide the following information:
- dataType
- description (optionally)
Example:
{
"model": "abb.ability.device",
"typeId": "my.type",
"version": "1.0.0",
"properties": {
"weight": {
"dataType": "number",
"description": "Physical mass of the object"
}
},
"variables": {
"speed": {
"dataType": "number",
"description": "Rotational speed of the object"
}
}
}
The actual object based on the type above could look as follows:
{
"model": "abb.ability.device",
"type": "my.type@1",
"properties": {
"weight": {
"value": 100
}
}
}
The "weight" property has been given a value. The "speed" variable is not visible on the object level because the values of variables belong to the Data Access domain of Ability Platform, and that's where you could retrieve them. The definition of both the property and variable allows only the numerical value to be included. However, number alone is not very useful. We need a unit.
{
"model": "abb.ability.device",
"typeId": "my.type",
"version": "1.0.0",
"properties": {
"weight": {
"dataType": "number",
"description": "Physical mass of the object",
"unit": "kg"
}
},
"variables": {
"speed": {
"dataType": "number",
"description": "Rotational speed of the object",
"unit": "rad/s"
}
}
}
The above is an example of enriching your type definitions with a "unit" attribute. Ability Platform Information Model allows you to specify your attributes on your data to give it some additional meaning.
Attributes Availability
Attributes may be used only if they were previously defined on your type in the "attributes" component. An exception from that rule are some predefined attributes (like "unit") that we will talk about later in this article. We'll show you how to define the attributes in the Custom Attributes section.
# Placement
Attributes may be defined for the following components:
- properties
- variables
- references
Mind that the attributes may be used for these components in both the type definitions (you can provide a default value there) and in the actual instances. For example, you could define that your "weight" property uses "kg" unit on the type definition level and overwrite that unit to "g" on the object level. As long as the attribute is available on a given type definition (more on that later), it can be used in:
- just the type (this way all instances "inherit" the specified attribute value)
- both the type and instance (instance overwrites the value specified in the type definition)
- just the instance (the attribute value is set only on that instance)
The following examples will show you how to use attributes in various places in the Information Model entities. For now (where it makes sense), we'll focus on one of the predefined attributes - "unit". This attribute (and some others that we will mention later on) does not need to be explicitly defined and can be used straight away.
# Properties
Properties are static data that characterizes your information model objects/instances.
# Type Definition
A property might have some attribute applied on the type definition level. That way, unless the attribute value gets overridden on the instance level, all instances of that type will have the "weight" property characterized by that "unit" set to "kg".
{
"model": "abb.ability.device",
"typeId": "my.type",
"version": "1.0.0",
"properties": {
"weight": {
"dataType": "number",
"unit": "kg"
}
}
}
# Object Instance
In this example, some instance of the type overrides the default value of the "unit" attribute with its own value.
{
"objectId": "d6198fa7-f0ca-4a31-b4ec-dd5ca3c172b1",
"model": "abb.ability.device",
"type": "my.type@1",
"properties": {
"weight": {
"value": 1000,
"unit": "g"
}
}
}
# Variables
Variables represent time-series data that your entities might generate.
# Type Definition
As in the case of properties, variables might define some default attribute value on the type definition level.
{
"model": "abb.ability.device",
"typeId": "my.type",
"version": "1.0.0",
"variables": {
"speed": {
"dataType": "number",
"unit": "rad/s"
}
}
}
# Instance
Again, object instances might specify attribute values for their variables.
{
"objectI": "d6198fa7-f0ca-4a31-b4ec-dd5ca3c172b1",
"model": "abb.ability.device",
"type": "my.type@1",
"variables": {
"speed": {
"unit": "rad/s"
}
}
}
# References
References represent connections between your object models. What such a connection means to you depends on your use case. You could represent various graph/tree structures that way.
# Type Definition
Attribute might be defined on the reference in the type definition itself. This way all actual reference instances will use that attribute value as a default.
{
"typeId": "my.type",
"model": "abb.ability.device",
"version": "1.0.0",
"references": {
"myReference": {
"to": [
{
"type": "another.type@2"
}
],
"attributes": {
"connectionInterface": "bluetooth"
}
}
}
}
Custom Attribute
The example above uses a custom attribute called "connectionInterface", because "unit" did not make much sense here. Such an attribute would need to be defined by the user in the same type definition where it was used. In the example, the attribute definition was skipped for readability, but we'll get back to it later in this document.
# Reference Instance
Individual references between two specific objects might also specify their own values for the available attributes.
{
"name": "myReference",
"to": {
"objectId": "22962836-06c3-468b-b131-84004308f499",
"model": "abb.ability.device"
},
"attributes": {
"connectionInterface": "ethernet"
}
}
In this case, this specific connection uses ethernet to connect two devices with each other.
# Predefined Attributes
Ability Platform Information Model comes with a few predefined attributes that you can use in your entities without defining them explicitly:
- unit
- max
- min
All other attributes need to be defined explicitly in your type definitions, as described in Custom Attributes.
These attributes, just like the custom ones, do not bring any Ability Platform-defined logic or meaning with them. It is up to you to decide if and how you want to use them and what meaning they would represent for you. The "unit" attribute is more or less universal and clear - most projects would probably use it similarly to add unit information to some property or variable. However, the "max" and "min" could mean different things depending on your use case, for example:
- min/max thresholds for some number value,
- min/max number of items in some array,
- min/max length of some string,
- or something completely different.
WARNING
It is important to clarify that the attributes do not have any meaning for Ability Platform services. It is up to you how you interpret the attributes of your data. For instance, the fact that you would define "max" = 5 for some numerical variable will not stop the Platform in any way from accepting values that are greater than 5. However, you could use that information in your services built on top of the Ability Platform to express somehow that the values are above the "max" attribute (maybe in the GUI of the application).
# Custom Attributes
If the predefined attributes are not enough in your case and you want to define your own, you can do that in your type definition. One example of such a custom attribute could be the "connectionInterface" attribute that we previously used in the reference example. References are a way to establish some relation in the graph of object models. These relations could bear some meta-data about them. In the presented example, we've used a reference to represent that some device is physically connected to another one. The connection might be established with various interfaces (e.g. Bluetooth, ethernet, RS-485, etc.). To express that in our modeling, we can define the following attribute:
{
"typeId": "my.type",
"model": "abb.ability.device",
"version": "1.0.0",
"references": {
"myReference": {
"to": [
{
"type": "another.type@2"
}
],
"attributes": {
"connectionInterface": "bluetooth"
}
}
},
"attributes": {
"connectionInterface": {
"dataType": "string",
"appliesTo": ["reference"],
"enum": ["bluetooth", "ethernet", "rs-485"]
}
}
}
This is a full type definition for the simplified example shown previously in the references. You can see both the definition of an attribute and its usage on the reference definition.
In the JSON you can see that we've defined the "connectionInterface" to be applicable only to references. Additionally, we've defined the type of attribute value to be a string. We've provided a list of accepted values in the "enum" field as a final touch.
TIP
We'll go deeper into what each field in the attribute definition means in a moment.
Now that you've seen this particular example let's see how you can use custom attributes in general.
# Placement
Attribute definition always has to appear in the type definition that intends to use it (or whose instances intend to use it). The attributes have to be placed in the "attributes" component of the type definition. Here's an example with multiple attributes defined:
{
"typeId": "my.type",
"model": "abb.ability.device",
"version": "1.0.0",
"attributes": {
"connectionInterface": {
"dataType": "string",
"appliesTo": ["reference"],
"enum": ["bluetooth", "ethernet", "rs-485"]
},
"urlType": {
"dataType": "string",
"appliesTo": ["string"],
"enum": ["absolute", "relative"]
},
"authoredBy": {
"dataType": "string",
"description": "Marks the author of a property/variable"
}
}
}
You can see that we've defined three attributes on that type definition. Note that we've only defined them and never actually used them - the type does not even have any actual data definitions (like properties, variables, or references). It is ok. We could add these in future versions of this type, or maybe we're just starting with this type definition, and we didn't yet define the actual data.
# Schema
# dataType
It is mandatory for each attribute to define its dataType. That part of the definition is used for validation. If I define an attribute with a "dataType" of string, I cannot use number, boolean, or other incompatible type with it.
TIP
The "dataType" field is all about the data type of the attribute's value. It has nothing to do with the type of the property/variable that that attribute is applied to. The latter case is covered by the "appliesTo" field.
Here's an example:
{
"typeId": "my.type",
"model": "abb.ability.device",
"version": "1.0.0",
"properties": {
"weight": {
"dataType": "number",
"authoredBy": "john.smith@pl.abb.com" // this value has to be a string
}
},
"attributes": {
"authoredBy": {
"description": "Marks the author of a property/variable",
"dataType": "string"
}
}
}
If you try to use an attribute and provide a value for it with a different data type than in the attribute's definition, such operation will be invalid, and the validation stage of your API request will fail (returning a 400 error).
# appliesTo
appliesTo is an optional field of the attribute definition. It's an array. It allows you to limit the applications of your attribute to the following options:
- specific data types:
number
integer
string
boolean
array
reference
You can combine options above. For example:
"attributes": {
"authoredBy": {
"dataType": "string",
"appliesTo": ["string", "number", "reference"]
}
}
The presented "authoredBy" attribute may be used with:
- properties that have "dataType" as one of the following: string, number;
- variables that have "dataType" as one of the following: string, number;
- references.
No limitations
If you do not include the appliesTo
specification in your attribute
definition, you will be able to use it with all properties, variables, and
references.
# description
An optional description field allows you to specify some string of text that explains the purpose of your attribute.
"attributes": {
"authoredBy": {
"description": "Marks the author of a property/variable",
"dataType": "string"
}
}
# enum
Optionally, with an enum field, you can limit the possible values that your attribute may have.
Example:
"attributes": {
"connectionInterface": {
"dataType": "string",
"appliesTo": ["reference"],
"enum": ["bluetooth", "ethernet", "rs-485"]
},
"urlType": {
"dataType": "string",
"appliesTo": ["string"],
"enum": ["absolute", "relative"]
},
"authoredBy": {
"dataType": "string"
}
}
In the example, we have specified the following:
- the "connectionInterface" attribute will be valid only if its value is one of: "bluetooth", "ethernet", "rs-485".
- the "urlType" attribute will be valid only if its value is one of: "absolute", "relative".
- the "authoredBy" attribute may have any value (as long as it's a string).
Another way to specify an enum
Instead of specifying some attribute's enum values "globally" for the entire type definition, you can also specify different enum options for different places where you intend to use the attribute.
{
"typeId": "my.type",
"model": "abb.ability.device",
"version": "1.0.0",
"properties": {
"linearSpeed": {
"dataType": "number",
"unit": ["m/s", "km/h"]
},
"circularSpeed": {
"dataType": "number",
"unit": ["rad/s", "deg/s"]
}
}
}
In the example, we used the predefined "unit" attribute. We've specified different possible values of that attribute per each property of our type. Instances of that type definition will have to adjust to the provided values of the enum.
The instance might also define the properties without providing any value for the "unit" attribute. Attributes are always optional.
# Summary
Attributes allow you to enrich your entities with meta-data that add meaning to your values. You can later use these values to provide more context to the systems that you build around your information model types.