Balancing act with data in Attributes, State, and Driver Data

In testing and by reading through the community history, I've learned about State, Attributes, and Driver Data. There seems to be a balancing act to be played out here, and in some cases it feels contradictory. I'm going to write out my own understanding through reading and testing, please correct me anywhere I'm wrong.

Driver data positives:

  • Retains data that the Driver and a linked App can use
  • Doesn't end up in the event log

Driver data negatives:

  • Shows at bottom of page and only after reloading a page so not useful for feedback
  • Not available for Rule Machine trigger/condition
  • Can not clear any value from Driver Data without removing the device entirely

So it's good for storing things the driver or the associated app might need regardless of state, but useless outside of that context.

State data positives:

  • Can store data ad-hoc, pre-creation not required
  • Can be cleared

State data negatives:

  • Changes visible only after reloading the page
  • Not available for Rule Machine trigger/condition

Very useful for storing data like tokens associated with a current login, etc that a user doesn't necessarily need to see. Useless for Rule Machine AFAICT.

Attributes positives:

  • Data shows on the screen high enough to be visible to the user (e.g. confirm login was successful)
  • Data can be used as a trigger/condition for Rule Machine

Attributes negatives:

  • Must be pre-declared, which makes it unusable for storing data about something we won't know until interacting with the device/service (e.g. how many Areas are defined in the alarm system?)
  • I can't find any way to change an attribute without also generating an event, and I agree with @mike.maxwell that a driver generating a dozen or more events during each interaction isn't helpful

If you'd rather read code than text, here's my code: hubitat-abode/AbodeAlarm.groovy at master · jorhett/hubitat-abode · GitHub

Any and all advice appreciated. Pointers to documentation or community threads I overlooked especially welcome.

I didn't get much of an answer when I posted this question a while back.

My short take on it after personal experiences may be irrelevant because it is not based on much more than personal experience but here it is anyway...

Updating attributes will always cause events, grow event logs, check for subscriptions, etc. There are possible performance implications so unless I have a good reason for wanting to check this value outside of the device I do not use an attribute. Otherwise, I put data in an attribute. Examples, I have put the websocket state in an attribute as well as current values for things that I want to be able to check from RM.

Updating device data seems to be slightly more tedious than using state so I have decided to put permanent and semi-permanent (like firmware versions) in data.

All the rest like data needed for day to day operations of the driver or gimmicky things (like instructions) I put in the state. As far as I can tell this is the cheapest place to store data. Then there is also atomicState which is essentially an atomic state as the name suggests. If you need to work out thread-safe code this can be used because the values are persisted immediately instead of lazily when the driver instance is cleaned up. Don't mix state and atomicState I've been told. I don't know why but I picture some real "don't cross the streams" scenarios although highly unlikely.

1 Like

Thanks for the detailed reply. That's pretty much the same balance I've found. Most of it I have no problem with, but if I'm dealing with an unknown number in advance (e.g. number of areas defined in the alarm) then the inability to dynamically define attributes bites me.

I'm going to guess that the right answer probably involves child objects, but that feels like overkill for this one use case.

Oh, and drivers can't apparently use atomicState in hubitat. Not sure that's a problem if drivers are always single-threaded.

Oh, that's true. atomicState can't be used in drivers. I forgot about that. At the end of the day I haven't needed to do any serialization in a device though.

If you want to define attributes dynamically I think you might be fighting the wrong battle. I have done quite a few different device types from having to integrate all the Ring devices into HE and a handful more other devices and I haven't seen a need for that. There is a finite number of values a device can report therefore a finite number of attributes you define up front should be good, no?

Abode doesn't have a published API. I can't find any docs that indicate how many alarm areas there can be.

After login, I can query how many areas are defined in the account. That's the only way to know. The only other 2 implementations of their API I can find don't know either -- they determine it dynamically just like I do.

There isn't one, an attribute that changes value is by a definition an event. Events are what drives an event driven system such as HE.
Perhaps the simplest way of thinking about this being, if the attribute serves no purpose as an automation trigger, then it shouldnt be an event...
Look at dumping this type of data to live logging instead.

1 Like

Oh, for groups of things that users create I use devices. I definitely wouldn't define those as attributes. With Ring devices you can group lights into groups. I use a device (sub-device) for that.

I understand this and I think I already have that balance correct in this driver (your thoughts are welcome if you think otherwise)

My problem with attributes is their static definition doesn't allow for interfacing with user-generated data-- like user-configured alarm zones/areas. If there was a way to generate the attributes from driver data or state, they could be significantly more useful.

The way I look at things,

state/atomicState is storage area used by the driver code. Stuff that will be persisted between executions or that need to be tracked. Storing token data is a good idea of what to store there. Its volatile as the state variable is a special list and can easily be modified or wiped (state.clear()) by code. It can also store all types of data. I can't remember if state data is accessible from parent apps/drivers without the use of a public method to grab it for you.

Data storage I use to store a small amounts of information about the device specifically. For example i would put manufacture information specific to the device or even a device id that I may have to pass along to the parent app. Previously I would store the device ID in the object id and parse it out before sending it but using data is much easier. Data can also only store strings. I believe this data is accessible for the parent app/driver.

Attributes, while you can create custom, are usually tied to capabilities. I don't use them to store data but to represent a state that the device is in. For example, on/off or playing/paused. I try to minimize my use of custom attributes and stick to the standard attributes. But I do have a few customs for personal reasons. These values are accessible from a parent app/driver.

These are the rules I follow when developing my drivers. Of course there are exceptions but its very rare that I have to implement them.

Actually you can totally remove a data value but it's a hack and messy. There are issues storing empty data in a value (or null).

State in drivers can be very troublesome and inconsistent , especially with rapidly changing values and atomicState can't be used in drivers. I have used attributes as replacement for state sometimes as they seem much better in this regard.

atomicState in applications is also not totally safe but so much better , but slower than state. However if you use one atomicState data value then all your values have to be atomicState as you mustn't mix state and atomicState.

How do you remove a data key?

I asked for a remove method (which is in progress) but in the meantime Chuck replied..

we don't have a method for it, I'll add it to the list of stuff to add, but there is a real hacky way to do it in the meantime, you have to have at least one extra data value in the data map for it to work, if you are trying to remove all the data values, it won't.

add data values:

    device.updateDataValue("myData1", "myDataValue1")
    device.updateDataValue("myData2", "myDataValue2")

data now looks like this:

remove 1 data value and update other value to force a save:

    device.data.remove("myData1")
    device.updateDataValue("myData2", "myDataValue2")

3 Likes

Great to know! Thank you, @kevin and @chuck.schwer!

Do you mean the ones which are associated with a capability? Or what definition of "standard" is there?

Ya. I try to only use attributes associated with a capability.

But there are always exceptions to the rule. It’s more of just a guide I follow.

FWIW I'd love to do that with the Abode alarm, but if I add the KeyPad capability I get a commands that don't function. It's probably one of the largest capabilities :frowning: Unless there is a way to suppress commands from being visible, it seemed like reinventing the wheel in that case was a better user experience.

There's real benefit to this... Apps allow users to select devices based on Capabilities, in so many cases. A Driver with just a "Sensor" capability (which has no attributes) and thus the driver is likely to be packed full of 'custom' Attributes, (even if they are spelled the same as their Capability attributes.)

Take HubConnect Apps as an example: it wants to have Every Device selectable under one selector or another. Yet a Device with only 'capability Sensor' would not be found in any Selector. (Custom dodges that pitfall.)

Drivers are supposed to use "sensor" or "actuator" as well as a 'defining' Capability, which would become the Selector in various Apps... be it Echo or Rule Machine. After that.. if Capabilities include undesired extras, then going the other way (individually defined Attributes and Commands) makes sense. In other words, if you're creating a driver for a keypad, but only use the "motion" capability, you will have successfully obscured selecting the device for many Apps, despite adding keypad Attributes and Commands back in, manually.

So... what I think I'm saying is.. I start out just like @gavincampbell and quite often end up just like @endorphin_junkie :smiley:

You will run across that a lot. For example, I may have volume controls but mute/unmute is not a command that works on the device. What I do is I code the methods but just so they don't kick an error if called and theydon't do anything. Then I just ignore the buttons.

The device page is not meant to be used as the interface to control the devices. So having a bunch of dead commands (even though they clutter the space and it hurts our ADD) doesn't hurt. The dashboards and in automation's is where they are to be controlled from.

And as @csteele you will really see why trying to use the standard capabilities is best when it comes to them being discoverable in app selection boxes. A lot of apps probably won't have the ability to fire off the custom commands or act on the custom attributes.

Well for this driver, you have to authenticate to the alarm service so having a useful UI is necessary for at least setup, and probably 1x a week if you use MFA.

Does this still work? I ask because it doesn't seem to be for me.