DynamicGroupController and attributes
-
Hey @toggledbits I'm back to trying to optimize a couple of things based on dynamic group.
First of all, I think I found a typo in the doc:
primary_attribute: "binary_sensor.state" primary_attribute_value: | d = false; each id in members: d = getEntity(id)?.attributes?.power_switch?.state or d, dI think the correct code snippet is
d = false,All that said, my use case for dynamic groups is to group 3 different climate devices, so I could easily command them at the same time. Commands are good, but sometimes I want to check if any of the devices are on, and that's easily done with a similar snippet as the one you have in the docs. But this is limited to the primary attribute, while I want to have any of the attributes in the group to be driven by a similar logic (while all are null in the group). ie, access
hvac_control.modeand see if any of the unit is set to cool, or heat. Is that possible, without re-defining an expression in each of my rules? Thanks! -
Hey @toggledbits I'm back to trying to optimize a couple of things based on dynamic group.
First of all, I think I found a typo in the doc:
primary_attribute: "binary_sensor.state" primary_attribute_value: | d = false; each id in members: d = getEntity(id)?.attributes?.power_switch?.state or d, dI think the correct code snippet is
d = false,All that said, my use case for dynamic groups is to group 3 different climate devices, so I could easily command them at the same time. Commands are good, but sometimes I want to check if any of the devices are on, and that's easily done with a similar snippet as the one you have in the docs. But this is limited to the primary attribute, while I want to have any of the attributes in the group to be driven by a similar logic (while all are null in the group). ie, access
hvac_control.modeand see if any of the unit is set to cool, or heat. Is that possible, without re-defining an expression in each of my rules? Thanks!@therealdb said in DynamicGroupController and attributes:
I think the correct code snippet is d = false,
The grammar allows semicolon (
;) to end a subexpression, so in that context, the two should be interchangeable.@therealdb said in DynamicGroupController and attributes:
But this is limited to the primary attribute, while I want to have any of the attributes in the group to be driven by a similar logic
I understand. Nice. I will look at this in greater depth over the weekend.
-
Yes!
Question on your feature request... generally, a capability has to be defined on an entity to assign an attribute within that capability. A Group is a subclass of Entity that normally has a limited set of capabilities and attributes that don't vary from group to group (i.e. the
sys_groupcapability is pretty much it).I can see adding attributes to a Group two ways:
- Like with actions, the capabilities the Group allows follows the superset of capabilities of the Group's members, so the group would inherit those capabilities and you would be allowed to set attributes (via expressions in config) for them, or...
- In config, you set what capability you want to assign and set attributes for, and then supply the logic (expression) to drive the attribute. In this scenario, the only additional capabilities that are assigned to the Group are those you explicitly name in config.
Thoughts?
-
Number 2 seems more logical. Right now all we have are empty values.
Maybe some way to do easy things like
- avg/min/max of values
- if any matches a value (ie cool), the value is cool
- and/or/xor for binary values
Similar to other options, to avoid code for simpler scenarios. Thanks.
-
Number 2 seems more logical. Right now all we have are empty values.
Maybe some way to do easy things like
- avg/min/max of values
- if any matches a value (ie cool), the value is cool
- and/or/xor for binary values
Similar to other options, to avoid code for simpler scenarios. Thanks.
@therealdb said in DynamicGroupController and attributes:
Number 2 seems more logical. Right now all we have are empty values.
I have this working, but I have had a busy week and then wife's birthday this weekend, so it might be another couple of days before I turn it loose. Just letting you know I haven't forgotten.
-
Here are the docs for what I have built thus far. Comments and suggestions on functionality appreciated!
Custom Attributes
In addition to setting the primary attribute for a dynamic group, users may add custom attributes to the group. The values of these custom attributes are typically derived from attribute values of the group's members. For example, a group of temperature sensors can have a calculated average of the readings of all the sensors.
Custom attributes are defined under the
calculate:object in a group's configuration. Here's a possible configuration for the example given above as a group with IDtemp_sensors. Theselectconfiguration simply selects all entities having thetemperature_sensorcapability, for illustration purposes (in practice, we'd probably want toinclude_entitysome specific entities for this purpose).temp_sensors: select: - include_capability: temperature_sensor calculate: - attribute: 'temperature_sensor.value' source: attribute: temperature_sensor.value # Where to get data values op: averageThis is the most basic form of custom attribute configuration. The
calculateobject is an array of configuration objects. Theattributekey is required for each array element and specifies the attribute to be defined and calculated on the group. Thesourcesubstructure tells DynamicGroupController what attributes on the member entities should be used for calculation. Any member entity that does not have the specified source attribute, or for which the attribute's value is null, is simply ignored. Theoptells DGC how to reduce (or aggregate) the multiple values from the member entities down to a single value. Pre-defined operations foropare defined below:opType Description average,avg,meannumeric The average (arithmetic mean) of the available values. mediannumeric The median of the available values (i.e. the middle value of the values when sorted). min,maxnumeric The minimum or maximum of the available values. sumnumeric The sum of the available values. countnumeric Count of non-null values. and,nandboolean Logical AND of available values. All values must be boolean true for the result to be true. If nandis used, the result is inverted (i.e. false when all values are true)or,norboolean Logical OR of available values. If any value is true, the result is true. norinverts the results (false when any value is true)xor,xnorboolean Logical XOR. Since more than two values may be considered, this operation is only true when exactly one of the values is true. If multiple are true, or all are false, the result is false. The xnorinverts the result.firststring Given a string or an array of strings to match in a valuekey (at the same level asop), this operation returns the first matching value. That is, each element ofvalueis checked to see if it matches asourcevalue from any of the group's member entities; if so, that element/value is the result; if not, the test moves on to the next element. If no match, null results.!!! note "null Member Attribute Values"
All of the above operations ignore null values from thesource, unless otherwise indicated.There may be circumstances where the
sourcevalues require some pre-conditioning or filtering. This is enabled by thevalue_exprsubkey undersource. The result of the expression is the value that will be added to the array of values foroporreduce_expr. For example, in our temperature sensor group, some of the sensors return temperatures in Celsius, and others in Fahrenheit. We can usevalue_exprto convert the values to a consistent unit, so that the resulting reduction operation yields a consistent value in that same unit:temp_sensors: select: - include_capability: temperature_sensor calculate: - attribute: 'temperature_sensor.value' source: attribute: temperature_sensor.value # Where to get data values # Convert Celsius temperatures to Fahrenheight value_expr: > local units = entity.attributes.temperature_sensor.units; local d = ( units === 'C' || units === '°C' ) ? value * 1.8 + 32 : value; ( d <= 0 || indexOf( ['C','F','°C','°F'], units ) < 0 ) ? null : d op: average prec: 2 # two decimal digit max resultStep by step, the
value_exprabove first fetches the member entity's temperature units into a local variable calledunits. Since theattributeundersourceistemperature_sensor.value, the context variablevaluewill contain the raw value from that attribute. The second line of the expression then checks if the units are Celsius, and if so, converts them to Fahrenheit (if units are not Celsius, it just takes the currentvalue) and assigns it to a local variabled. Finally (third line of the expression), if the value is in range and the units are known, the value ofdis returned, otherwise null. As stated above, most of the predefined operations ignore null values in their computation. Sovalue_exprcan function both to condition values and to filter them.The
preckey allows you to define the number of decimal digits precision for the result value; the result is rounded to comply. For example, a calculated value of 3.14159265 withprec: 4results in 3.1416.If none of the pre-defined operations addresses the need, the
op:key can be replaced with an expression defined byreduce_expr:. The result value of the expression will be the value assigned to the custom attribute. The context forreduce_exprincludes the following variables:grouprefers to the group entity being defined;membersis an array of canonical IDs of the member entities at the time of evaluation (which may change in a truly dynamic group); andvaluesis an array of the member values (as derived fromsource).temp_sensors: select: - include_capability: temperature_sensor calculate: - attribute: 'temperature_sensor.value' source: attribute: temperature_sensor.value # Where to get data values # Compute harmonic mean (not predefined) using expression (trivialized for illustration) reduce_expr: > local s = 0; each v of values: do s = s + (1.0 / v) done; len(values) / s prec: 2 # two decimal digit max resultFinally, custom attributes that should have fixed values can be defined by simply supplying
value:undersource:, like this:- attribute: 'temperature_sensor.units' source: value: '°F'Make sure the data type of the
valueconfigured matches the expected type of attribute being defined.











