-
Notifications
You must be signed in to change notification settings - Fork 0
Entity States
V10.1
HaKafkaNet is driven by state changes published by Home Assistant. Here's an example of a typical state from a light pushed by Home Assistant into Kafka:
{
"attributes": {
"brightness": 41,
"color_mode": "brightness",
"friendly_name": "Office Lights ",
"supported_color_modes": [
"brightness"
],
"supported_features": 32
},
"context": {
"id": "01HQ41SDCE9VZ1KVH1E9E6Q5YG",
"parent_id": null,
"user_id": "[redacted]"
},
"entity_id": "light.office_lights",
"last_changed": "2024-02-20T15:02:21.297491-05:00",
"last_updated": "2024-02-20T15:02:21.297491-05:00",
"state": "on"
}
The top level properties and context properties will always be sent. The state will be a string, but could represent a number depending on the entity. For example power meters or plugs with power reporting capabilities will typically put a decimal number in the state. The attributes sent are completely up to the integration which exposes the device and its entities.
Non-generic automations are sent an HaStateChange<HaEntityState>
.
Generic automations are sent HaStateChange<HaEntityState<Tstate,Tatt>>
public record HaEntityStateChange<T>
{
public required EventTiming EventTiming { get; set;}
public required string EntityId { get; set; }
public T? Old { get ; set; }
public required T New { get ; set; }
}
The Old
and New
properties will represent states as exposed by Home Assistant and shown above. The value of Old
will always represent what was previously stored in the cache or null if it was not found in the cache. The New
property will always represent the state of the entity being read from Kafka.
See Event Timings for more information on the
EventTiming
property.
The instances of HaEntityState
sent to non-generic automations derive from HaEntityState<string, JsonElement>
where the generic properties represent the state and attributes respectively. Here is a simplified definition of HaEntityState<Tstate, Tattributes>
.
public record HaEntityState<Tstate, Tattributes>
{
[JsonPropertyName("entity_id")]
public virtual required string EntityId { get; init; }
[JsonPropertyName("last_changed")]
public DateTime LastChanged { get; init; }
[JsonPropertyName("last_updated")]
public DateTime LastUpdated { get; init; }
[JsonPropertyName("context")]
public HaEventContext? Context { get; init; }
[JsonPropertyName("state")]
public virtual required Tstate State { get; init; }
[JsonPropertyName("attributes")]
public Tattributes? Attributes { get; init; }
}
There are several State extension methods to help with converting the raw HaEntityState
into one that is strongly-typed for your needs, for example ToColorLight()
returns HaEntityState<OnOff, ColorLightModel>
. Under the hood, this conversion is done with an explicit cast.
HaEntityState rawState = null; // from an entity provider or passed into an automation
HaEntityState onOffState = (HaEntityState<OnOff, ColorLightModel>)rawState;
The helper methods are there so you don't need to remember all the combinations of Tstate
/Tatt
, and there are helper methods for you to choose the types you want also.
Note: Type conversion for entities returned from the Updating Entity Provider are not done with a hard cast. However, the considerations are very similar to what is described here.
The cast operation can throw an exception if the conversion cannot happen.
Imagine if you wanted an HaEntityState<float, JsonElement>
for a temperature sensor, but the sensor is offline, and so its "state" property in Home Assistant is "unavailable". In that case "unavailable" cannot be converted into a float
and so an exception will be thrown.
That is why the ToFloatTyped()
method returns HaEntityState<float?, JsonElement>>
. Since the State
property is nullable, instead of throwing an exception, it sets State
to null
.
Several built-in enums account for this possibility. For example, the OnOff
enumeration, commonly used for switches and contact sensors, has values that represent "unknown" and "unavailable". Therfore, the ToOnOff()
method returns HaEntityState<OnOff, JsonElement>
. Notice that OnOff
is not OnOff?
.
Note: When creating your own enums, for example when using a drop-down helper entity, it is recommended that the first two values be
Unknown
andUnavailable
if you will be using them as the state of an entity.
In most cases, for non-enum value types, you likely want to choose a nullable type, especially when using the IUpdatingEntityProvider
. The one exception to this may be when creating a generic automation and you have TriggerOnBadState
set to true
for your AutomationMetaData
. When using a generic automation, you can choose to implement IFallbackExecution
which has a method that will be called when conversion fails. In this case, if you implemented IAutomation<float?, JsonElement>
and the state was "unavailable", the conversion wouldn't fail, and the fallback method would not be called.