The purpose of the mapping engine define relations between attributes in the attribute store, in general the relation between the Z-Wave attribute and the Zigbee attributes. The actions performed by the mapping engine is quite similar to the actions performed by a compiler. A compiler parses a text document and builds an Abstract Syntax Tree(AST). The AST is then optimized and the AST nodes are translated into machine op codes. In the attribute mapper we are not translating AST nodes to opcodes but instead we are keeping the AST in memory.
The mapping engine only interacts with the attribute store. An example of a simple mapping is the relation between the zigbee attribute OnOf.value and the Z-Wave attribute binary_switch.value, if desired of OnOf.value is update the binary_switch.value should be update. The the same applies to the reported value in the reverse direction. So in a meta description we could describe this behaviour with the following:
This means when the reported value of BinarySwitch_Value changes we would like to update the repported value of OnOff_Value. Actually we will also create the OnOff_Value if it does not exists (this will only happen with reported values). For the desired value we update BinarySwitch_Value if OnOff_Value changes.
For simplicity the attribute mapper evaluates every thing as int32. This mean that All attributes the mapper deals with must be int32.
The AST of the rule set is stored in memory because when an attribute changes, we should locate dependencies using the AST. The value of each AST node can be calculated in the context of an attribute node. Let's look at the example where an attribute is updated and the node type of that attribute is a leaf nodes in the AST. Then we need to try to re-calculate the value of all AST nodes that depends on the updated node. The update may lead to a write of another attribute. In the example above an update leads to an update of the OnOff value. There could be cases where some node in the AST cannot be evaluated in a given context, for example if one attribute depends on two other attributes but only one of them is defined. Then the AST will not be fully evaluated in the given context (the node does not support all the required command classes). In this case the update will not lead to an attribute write.
In some cases there could be multiple ways to calculate a mapping. Let's take a fictive example of some ZigBee LED color command class. On the Zigbee side colors are defined as RGBW on the Z-Wave side the color may be in RGBW or may be in just RGB.
Here we would persue the relation using zwColor[W] first, if that is not possible we would fall back to ((zwColor[R] + zwColor[G] + zwColor[B])*1000) /3333
The mapping engine uses a number of C++ classes to perform its tasks.
The ast::UAMGrammar class defnies how we translate a text document into our ast using the boost spirit framework.
The ast::dep_evel class is used to build a graph of relations between attributes.
The ast::eval class is used to evaluate expressions when a change in a attribute value occurs