Capabilities describe a device. This allows Apps to find devices that contain certain capabilities and know what attributes (variables) and commands (functions) that device supports. Basically, Capabilities define the interface for a device.
Attributes are the variables/values exposed by a device. These are updated by creating/sending Events. Any Apps that are subscribed to these events will be notified when the value of an attribute changes. This is the basis for the event driven model of ST/Hubitat.
Devices may also contain custom Commands and Attributes, that are not part of a Standard Capability. This provides additional flexibility to the system, however standard Apps will have no way to know about these custom features. RM recently got the feature to call Custom Actions (I.e. custom commands) in a device. This is very useful when using custom, non-standard devices.
The WHY for these is basically to create the standard architecture of the platform. These constructs form the basis for the design of App and Drivers, necessary to keep developers all between the same set of “guard-rails”, versus it being the “Wild West” of code design.
As long as my custom Drivers follow this standard architecture, any App can be used to interact with my devices.
If you created a custom driver and did not list temperature from your example as a capability, then any app - built-in or custom - or RM that wanted to do something say based on temperature, said device would not be available to select to use.
Capabilities define the device in terms of the commands that are available and expected to be there as well as the attributes associated with the capability.
When a device attribute value changes it is considered an event, this is then sent to the system.
FuelGauge: 0 to 100
Operating state: running, parked, idling...
Commands: start, stop
Capabilities have a mandated list of Attributes and Commands.. something the System can rely on. If you indicate there's a Switch Capability, you better implement both On and Off. You could invent a switch that doesn't do off, but you must have a method for Off that does nothing.
Commands alone (not part of a Capability) are similar. You declare one, you must have a method for it and will be found via Custom Commands. (or now Custom Actions)
Attributes alone (not part of a Capability), are just entries in the internal DB.. if you want to read them, you really should put something in there, but there are plenty of Attributes that don't I'd imagine. For example... I create a driver and add an Attribute of Version. Then later I define and use version (lower case) -- then the first one will be there forever, unused (Or the cause of a problem )
The best way to wrap your head around all of this is to look at some of the drivers in the forums that have been written by members here.
Look at the metadata section at the top of the driver and look at the capabilities, commands, and attributes. Then look through the code and see how it all interacts with each other and how the different events are created and attributes updated, etc.
Most attributes in drivers can be exposed in a Dashboard tile and displayed. So if you created a custom driver to do something unique to your use case, then you could expose and display that attribute in a Tile or use it internally in your app or driver.