HassController
HassController is the interface to Home Assistant systems. It uses Home Assistant's WebSocket API to implement the communications layer. This approach significantly reduces the load of communication on both systems, even in periods of high activity when a lot of data is being exchanged. You will need to make sure that the WebSocket API is enabled in your HomeAssistant configuration. See their documentation for that.
Because Home Assistant sometimes makes breaking changes to its API, only specific version of Home Assistant are supported by this interface. Currently, only Home Assistant versions 2023.6.0 through 2024.10.4 are supported. Versions outside this range may not work at all, or exhibit errant behaviors that are not immediately obvious. Bug reports and fixes for versions outside this range are not accepted/handled.
The only required fields for HassController are source
and access_token
:
reactor:
# reactor configuration section not shown
controllers:
- id: hass
enabled: true
implementation: HassController
name: Home Assistant
config:
source: "ws://192.168.0.10:8123"
access_token: "place long-lived access token within"
Note that the source
field must contain a URI in the form ws://ip-address:port
. The access_token
value is a "long-lived access token" from Home Assistant. To get a LLAT, log in to the Home Assistant UI and click on your username in the bottom-left corner. Then scoll down your profile until you find the "Long-Lived Access Tokens" section. Create a new token there, and copy/paste it into your Reactor controller configuration, keeping it surrounded in quotes as shown above.
Attention
Make sure that the Home Assistant http
and websocket_api
components are properly configured and enabled. If you have enabled SSL/TLS in your http
component configuration (i.e. you specified ssl_certificate
in your http
configuration in Hass), you must use wss://
on your source
value in reactor.yaml
, and, if you are using a self-signed certificate, you will also need to add ignore_cert: true
after source
.
Mapping Home Assistant Entities to Reactor Entities
HassController tries to do as much of the work of mapping between Home Assistant entities and Reactor entities as possible through configuration files. However, there is some data that is not available through the Home Assistant APIs, so there is a mechanism by which you can either override or enhance HassController's default mapping strategy.
Your overrides and enhancements can be specified in a configuration file you create and manage called local_hass_devices.yaml
. This file must be located in your config
subdirectory (where reactor.yaml
also resides).
Overriding Entity Name, Capabilities, etc.
To override the name of an entity, or to add a capability that an entity may have that does not register automatically, add the entity to an entities
section of local_hass_devices.yaml
, like this:
entities:
"hass>switch_power_switch":
name: "My Override Name"
services:
- light
- button
capabilities:
- temperature_sensor
primary_attribute: temperature_sensor.value
In the example above, the entity with the (Reactor) canonical ID hass>switch_power_switch will get given the name shown instead of the name it has in Home Assistant. The services:
section (optional) tells Reactor what if any additional (Home Assistant) services the entity provides. This may be needed because (sadly) Home Assistant does not enumerate supported services for its entities in its API — there's no way for Reactor to know what services apply except for the one service that is used to form its entity ID. The (optional) capabilities:
section tells Reactor what additional Reactor capabilities to extend to the entity (if any); in this example, we're saying that this odd entity also has temperature sensor capability. Finally, this example makes the temperature sensor value the default (primary) value for the device.
Services First
If you can, use the services
section as your first effort to get full entity capabilities. Some Home Assistant services map to multiple Reactor capabilities, so by naming the services first, Reactor is able to correctly find and apply all of those capabilities. If, after naming the services, you don't have a needed native Reactor capability (i.e. not including the x_
extension capabilities), please report that to me on the SmartHome Community so I can improve the device mapping.
Filtering Entity Data
Sometimes, Home Assistant entities will update some of their data fields frequently, and this can cause Reactor to throttle rule evaluation when the rule uses that entity in a condition. To reduce "noise" data from Home Assistant, you can use an extended syntax of the filter_entity
configuration to filter out specific attributes.
Let's say we have an IP camera that has motion detection, and on windy days, the shadows moving in the room from the sun passing through the wind-blown trees causes the motion sensing to trip repeatedly, and that causes spurious evaluation of rules that are using other camera attributes. Using the Developer Tools page in Home Assistant, we can look at all of the state attributes for the camera and discovery it contains these attributes:
model_name: IP2M-841EW
brand: Amcrest
motion_detection: true
frontend_stream_type: hls
audio: on
motion_recording: on
color_bw: auto
entity_picture: /api/camera_proxy/camera.cam2?token=
friendly_name: Cam2
supported_features: 3
The camera's motion_detection
attribute is the value that is constantly changing between true and false, so we just want to ignore that attribute. We add the following configuration to the config
section for our HassController instance:
``` yaml hl_lines=6-8 - id: hass enabled: true implementation: HassController config: source: "ws://192.168.0.10:8123" filter_entity: camera.cam2: - motion_detection
This tells *HassController* to ignore the `motion_detection` state attribute on its entity `camera.cam2`. After restarting Reaction, this attribute will no longer be considered for updates, and have no effect on the Reactor entity or attributes — and the excess rule evaluations will stop.
The items under the entity ID (`camera_cam2` in this example) are array elements, and each array element is the name of a state attribute from *Home Assistant*'s list of state attributes for that entity.
Filtering out data isn't the appropriate choice for every situation. If, for example, you have a home weather station that sends updates every few seconds, and you need to use that data rather than filter (discard) it, you can use the features of *VirtualEntityController* to create a time series and apply some kind of aggregating function, like a weighted average over some period, to make the data more manageable.
## Handling Home Assistant Events
Some Home Assistant devices send events, and these events are not mapped in Home Assistant to a Home Assistant Entity. Since the Home Assistant API does not enumerate these events or the devices that may send them, it is up the user (you) to add event handling for any such events.
For example, let's say you have an Amcrest camera that can do motion detection and sends motion events, but the HA integration does not create a virtual motion sensor entity to reflect the state of that capability, it only sends events. Here's a typical motion-start event for the camera:
``` json hl_lines="2-5"
{
"event_type": "amcrest",
"data": {
"camera": "Cam2",
"event": "VideoMotion",
"payload": {
"Code": "VideoMotion",
"action": "Start",
"index": "0"
}
},
"origin": "LOCAL",
"time_fired": "2021-11-16T19:25:10.223198+00:00",
"context": {
"id": "9ec3cdea4a733798660e23e2f59b3a2e",
"parent_id": null,
"user_id": null
}
}
The four highlighted lines above are going to be used to detect this event. We add the following configuration to our HassController's config
section of reactor.yaml
:
config:
# Additions to config section for Amcrest camera motion:
event_targets:
cam2_motion:
capabilities:
- motion_sensor
events:
- event:
event_type: amcrest
data:
camera: "Cam2"
event: "VideoMotion"
response:
"motion_sensor.state":
from: "lower(event.data.payload.action)"
map:
start: true
stop: false
This will create a (Reactor) entity with ID cam2_motion
, having the single capability motion_sensor, that responds to amcrest HA events. If an amcrest event is received that also matches the given data filters (the four highlighted lines above, which match the values in the four highlighted lines of the event JSON shown earlier), the attributes enumerated in response
will be updated in accordance with their configuration. In this case, that takes the value from the event's data and maps it to a boolean value as required for the attribute.
Each event
in the events
section (detailed fully below) contains a number of keys and values that are used to filter events. The subkeys of event
are compared to the data received. The comparison is literal and case-sensitive; regular expressions are not supported here. In the example above, the event_type
field and the data
subfields camera
and event
are compared to the event data. If the match is successful, the response
configuration is processed.
Note that the event_type
and data
values are dependent entirely on the event data for the device and integration in Hass, and they will vary. You can add log_events: true
to the config
section of your HassController instance to capture events to a file in your logs
directory, to help you determine what data Hass is sending with the event and what the filter values and expressions should be.
Large logs!
Turning on event logged will log a lot of data, because Home Assistant processes a lot of events. This setting should be enable only while you are working on an event configuration and turned off immediately after. A restart is required, of course, when the configuration setting is changed.
The response
section is an object the keys of which are attribute names in the target entity. Each attribute name must be fully specified as a capability_name.attribute_name
pair (e.g. power_switch.state
). That value for the key is an object containing instructions for setting the attribute value, which are derived from a combination of from
, map
and expr
keys. The from
key may be used to take a value from the event data received. The top level of the event received is represented by the event
name in context; for example, using the sample event data received above, one could access the action
field in the event data as event.data.payload.action
. The event
context variable also exists in the expr
key, so referring to event.data.payload.action
in the value of either from
or expr
produces the same result; the difference is that from
only allows a member reference in the event data (just the path to a field), where expr
allows any expression, so you could modify the value before it is assigned to its target attribute. Also note that expr
and from
are mutually exclusive; you cannot use both, and if both happen to be configured, only expr
will be honored. The map
key accepts from/to pairs; when the derived value matches the from string, it is changed to the to string. This mapping, if configured, is done last, after any from
or expr
.
The generalized form of the event_targets
section is:
event_targets: # this section starts the event-receiving entities
"my_virtual_entity_id": # Assign an ID to your entity; each entity must have a unique ID
name: "My Entity Name" # This is optional but recommended, so you have a friendly name
capabilities: # define an array of capabilities to be modified by the event
- capability_name # first capability
- capability_name # second, etc., as many as you need, but always at least ONE
events: # define an array of events that modify capability attributes on the entity
- event: # start of an event; each element of the events array begins this way
event_type: "type of HomeAssistant event"
data: # optional section, if further matching to the event data is required
data_field: "data_value" # data field to be checked/matched to data_value
data_field: "data_value" # as many as you need, but each data_field must be unique
response: # begin the (required) response section for handling the event
"capability.attribute": # an attribute that the event modifies.
expr: "expression" # expression to get attribute value from event data
"capability.attribute":
# This shows an alternative to using "expr"/expressions for value handling
from: "event.data...." # dot-reference expression to pull value from event message
map: # optional, map to modify value
value_in: new_value # if value is value_in, it is mapped to new_value
value_in: new_value # repeat this as needed, but each value_in must be unique
# repeat "capability.attribute" section for all attributes modified by the event
- event: # start of next event for this entity, if any; same form as above
"my_second_entity": # ID of next entity to create/handle events
events:
# etc...
Note that in the expr
expression, the variable entity
(object) is available with the current data/structure of the target entity. This allows you to access the current value of attributes on the entity while computing the new value, if that's relevant. As stated above, the event
variable (object) is also available with the full, raw data of the received event.
Service Call Responses
Some Home Assistant services can return data to Reactor. These services can be accessed using either the entity-specific service call (recommended; see the list of actions for the Reactor entity using the detail view on the Entities page) or using the generic call_service
action on a specific entity or the controller system entity. A service that has identified as response-capable will present with a "Capture response to" selector (dropdown menu) in the Entity Action(Entity-Action.md) of a Reaction. That will allow the service response to be captured in a variable, which can be a rule-based variable or global variable (expression-less). The response can then be further processed as needed using Script Action actions in the Reaction, used in substitutions, etc.
Other Special Configuration for HassController
This section is informational only. It is not usually necessary to specify these values or modify their defaults.
timeout
— this value sets the length of time HassController will wait for a successful connection to Home Assistant before throwing an error. The default is 15000 (milliseconds, 15 seconds).
Updated 2024-Oct-19