The difference is really quite simple but also technical. In the early days of Home Assistant, there were only entity id. It was generated automatically by combining a domain (e.g.
switch) and generally a “slugified” name (e.g. “Living Room Window” -> living_room_window). So a light in the living room window would become
light.living_room_window for instance. There are a few problems with this however.
If you have two “things” that happened to generate the same entity id, you would get one with the expected entity id and another one with
_2 appended to it. Depending on which got initialized first, you wouldn’t know which one is which. It wouldn’t necessarily be possible to change that either. Another thing is that you bind some configuration settings to an entity id, rather than a device. So if you change for instance the icon or another attribute, those would still apply to the entity even if you switched hardware (and used the same name, so the same entity id was generated). That might be expected behavior, but not necessarily.
To kind of fix this, Home Assistant needs a way to map internal configuration to a particular device without residing to things like name. Entity id and name should not need to have any correlation since you might want to use English names for entity id, but a localized name for presentation. That is what
unique_id is for. It is a unique identifier that identifies one specific device. Examples in this case are serial numbers, MAC addresses, or some other kind of unique identifier provided by the device. An IP address is a good example of the opposite, as it’s not uncommon that a device can change IP address due to DHCP lease. Such a thing must not change
By having an identifier that is unique per device, Home Assiatant can store configuration for that specific device. That’s why you can change entity id for an entity that supports
unique_id, but not for one that doesn’t. Other things like icons, unit of measurement and so on can be applied in the same way.
As a last note… You never deal with
unique_id yourself. It’s used internally by Home Assistant. Unless you develop things with/for Home Assistant, you don’t need to know what it is.