0.3.0
Added
Hassock.command/4sends any WebSocket command and waits for its result (:timeoutoption, default 10 s).- Registries:
Hassock.Registries.list_floors/2,list_areas/2,list_devices/2,list_entities/2andlist_labels/2, decoding into the newHassock.Floor,Hassock.Area,Hassock.Device,Hassock.EntityEntryandHassock.Labelstructs. Hassock.RegistryCache: the five registries in ETS, re-listed (debounced) on their update events and after every reconnect.Hassock.Supervisorstarts one withregistries: true(name it with:registry_cache_name).- The
*_registry_updatedevents arrive as{:event, {:registry_updated, kind, action, id}}(Hassock.Protocol.registry_event_types/0lists them). return_response: trueon%Hassock.ServiceCall{};call_service/3takes a:timeoutoption.Hassock.status/1(status, failed attempts, next retry time), andHassock.watch/1/unwatch/1(lifecycle messages for processes other than the controller).:toand:timeoutoptions onsubscribe_entities/3andsubscribe_events/3;:tosends a subscription's events to a given pid instead of the controller.{:subscription_lost, id, error}when HA refuses to restore a subscription after a reconnect.%Hassock.Config{}fields:ssl_options,ping_interval,ping_timeout,backoff_initial,backoff_max,connect_timeout; invalid values makestart_link/1fail with{:invalid_config, key}.Hassock.Cachepasses{:auth_failed, reason}on to its controller.
Changed
These change behaviour for 0.2 code:
Hassock.Connectionis a GenServer that owns a WebSocket process per connection attempt.start_link/1returns before the connection is up (it used to block, forever if Home Assistant was down); wait for{:hassock, conn, :connected}before sending commands.- Reconnects back off exponentially with jitter (1 s doubling to 30 s)
instead of retrying in a tight loop, and
{:disconnected, reason}is sent once per outage instead of once per attempt. The backoff resets once a connection has stayed up forbackoff_max. - An attempt that hasn't authenticated within 15 s is abandoned, and a subscription restore HA doesn't answer within that time re-makes the connection.
- Subscriptions are restored after every reconnect and keep their ids.
Code that resubscribes on
:connectednow gets duplicate subscriptions; remove it. - A keepalive ping every 30 s; a missing pong re-makes the connection.
- After
auth_invalidthe connection stops retrying (Home Assistant bans IPs after repeated failed logins). A controller set afterwards still gets{:auth_failed, reason}. - When the controller exits, any process may take control with
controlling_process/2(before, nobody could). - A subscribe whose caller timed out is cancelled at HA when its result arrives, and events for cancelled subscriptions are dropped instead of reaching the controller.
get_states/1andget_services/1return{:error, {:unexpected_result, result}}for a malformed result instead of crashing the connection.inspect/1of%Hassock.Config{}leaves out the token andssl_options.wss://connections verify the server certificate against the system CA store. Without a store, a warning is logged and the certificate isn't verified; setssl_options. URL schemes are matched in any letter case.- Events without an
event_typeare decoded assubscribe_entitiesupdates only when they carry just thea/c/rkeys; others (for example arender_templatesubscription made withcommand/4) arrive whole as{:other, nil, raw_event}(parse:{:event, id, nil, event}). Hassock.Protocol.parse/1returns pongs as{:pong, id}(was:pong), so a"ping"sent withcommand/4gets its answer.Hassock.Protocol.parse/1returns every result as{:result, id, success, result}; the{:states, ...}and{:services, ...}variants are gone (Hassock.Protocol.decode_states/1andHassock.Protocol.decode_services/1decode them). Invalid JSON returns{:invalid, error}instead of raising.Hassock.Cachediffs the snapshot that follows a reconnect against its table: entities removed during the outage are deleted, and a:changesmessage with the difference comes before:ready.Hassock.Cachereads go to ETS without calling the cache process.- Message ids keep increasing across reconnects instead of restarting at 1.
- Calls on a registered name with no process return
{:error, {:connection_down, :noproc}}instead of raising. Hassock.Supervisorwithcache: truestarts the connection without a controller, so no message reaches the supervisor before the cache claims it.
Fixed
- Results were decoded by their shape, so an entity registry list (a list
of maps with
"entity_id") or an empty list was dropped and the caller timed out. Results are now decoded by the command that was sent. - A malformed frame no longer crashes the connection.
Hassock.Cachekept rows for entities deleted while disconnected.
0.2.0
- websockex 0.5.
- CI gates (Credo, Dialyzer, Sobelow, hex audit, Argus) and the fixes they raised, including the controller monitor being re-added on every reconnect.
0.1.x
- Initial releases:
Hassock.Connection,Hassock.Cache,Hassock.Supervisor. 0.1.3 fixedHassock.Cachedropping events when started through the supervisor.