hass
hass copied to clipboard
An Emacs package for interacting with Home Assistant
#+TITLE: hass
[[https://melpa.org/#/hass][file:https://melpa.org/packages/hass-badge.svg]] [[https://stable.melpa.org/#/hass][file:https://stable.melpa.org/packages/hass-badge.svg]]
#+HTML: 
~hass~ is an Emacs package that enables integration with [[https://www.home-assistant.io/][Home Assistant]]. Call Home Assistant services, hook into Home Assistant events, and create convenient dashboards!
- Contents :PROPERTIES: :TOC: :include all :force ((nothing)) :ignore (this) :local (nothing) :END: :CONTENTS:
- [[#installation][Installation]]
- [[#use-package][use-package]]
- [[#straightel][straight.el]]
- [[#doom-emacs][Doom Emacs]]
- [[#version-3-changes][Version 3 changes]]
- [[#brand-new-dashboards][Brand new dashboards!]]
- [[#hass-dash-layout-is-now-hass-dash-layouts][hass-dash-layout is now hass-dash-layouts]]
- [[#hass-setup-no-longer-required][hass-setup no longer required.]]
- [[#removed-deprecated-name-widget-property][Removed deprecated :name widget property.]]
- [[#removed-polling-mode][Removed polling-mode]]
- [[#configuration][Configuration]]
- [[#getting-an-api-key][Getting an API Key]]
- [[#dashboard-layout][Dashboard layout]]
- [[#full-example][Full example]]
- [[#structure][Structure]]
- [[#widgets][Widgets]]
- [[#state][State]]
- [[#button][Button]]
- [[#toggle][Toggle]]
- [[#usage][Usage]]
- [[#dashboard][Dashboard]]
- [[#payloads][Payloads]]
- [[#hooks][Hooks]]
- [[#license][License]] :END:
[[file:images/screenshot1.png]]
- Installation This package is available on [[https://melpa.org/][MELPA]].
** use-package
#+BEGIN_SRC emacs-lisp :results none (use-package hass :ensure t :init ;; -- Configuration goes here -- ) #+END_SRC
** straight.el
#+BEGIN_SRC emacs-lisp :results none (straight-use-package 'hass) ;; -- Configuration goes here -- #+END_SRC
** Doom Emacs
Place in your ~packages.el~ then run ~doom sync~ to pull the repository:
#+BEGIN_SRC emacs-lisp :results none (package! hass) #+END_SRC
Then load the package in your main config file.
#+BEGIN_SRC emacs-lisp :results none (use-package! hass :init ;; -- Configuration goes here -- ) #+END_SRC
- Version 3 changes ** Brand new dashboards! Thanks to [[https://github.com/cprussin][cprussin]], the dashboards have been completely overhauled. They're much more flexible by more cleanly utilizing the built-in widget framework. Additionally, you can have multiple dashboards configured.
** =hass-dash-layout= is now =hass-dash-layouts=
** hass-setup no longer required. Calling ~hass-setup~ is no longer required. It has been renamed ~hass-ensure~. It can still be useful if you want to 'ensure' an API connection has already been established and entity information is already up to date before you open a dashboard.
** Removed deprecated :name widget property.
** Removed polling-mode Didn't seem useful.
- Configuration
Both ~hass-host~ and ~hass-apikey~ must be set to use this package. Set ~hass-host~ to the hostname or IP of Home Assistant instance. If you are not using SSL/TLS to connect to your Home Assistance instance, set ~hass-insecure~ to ~t~. If you are using a port number other than the default =8123=, specify the port number with ~hass-port~.
#+BEGIN_SRC emacs-lisp :results none (setq hass-host "homeassistant") (setq hass-apikey "APIKEY-GOES-IN-HERE") (setq hass-port 8123) #+END_SRC
Alternatively, you can store a function inside ~hass-apikey~. This will be executed on every query. In turn, this approach requires the token to be stored in your gpg store e.g. =~/.password-store/emacs-apikey.gpg=
#+BEGIN_SRC emacs-lisp :results none (setq hass-host "homeassistant") (setq hass-apikey (lambda () (auth-source-pass-get 'secret "emacs-apikey"))) #+END_SRC
Once those variables are set, you can call ~(hass-ensure)~ to query the Home Assistance instance and populate available entities and services. Otherwise, this will be done when it is needed. ** Getting an API Key
Ensure that your Home Assistant instance is configured to support API calls by following the instructions [[https://www.home-assistant.io/integrations/api/][here]].
Retrieve your API key a.k.a. /Long-Lived Access Token/ by logging into your Home Assistant instance and going to your profile by selecting your username in the lower-left corner or going to this URL: =http://HOME-ASSISTANT-URL:8123/profile=. You can generate an API token at the very bottom of this page.
** Dashboard layout
*** Full example #+BEGIN_SRC emacs-lisp :results none (setq hass-dash-layouts '((default . ; Key for dashboard. Shows up with completing-read when calling `hass-dash-open'. ((hass-dash-group ; Create a widget group. :title "Home Assistant" ; Give the group a title at the top. :format "%t\n\n%v" ; %t is where the title goes and %v is the widget it owns. (hass-dash-group ; Create a subgroup of widgets. :title "Kitchen" :title-face outline-2 ; Give it a unique face to make it stand out. (hass-dash-toggle :entity-id "light.kitchen_lights") (hass-dash-toggle :entity-id "light.master_bedroom_lights") (hass-dash-toggle :entity-id "switch.entry_light" :label "Hallway" ; Override the widgets friendly name :confirm t))) ; Require a y/n confirmation when toggling this entity. (hass-dash-group :title "Group 2" :format "\n\n%t\n\n%v" (hass-dash-toggle :entity-id "light.master_bedroom_fan_light"))))
(simple . ; Declaring a top-level group is optional and implied.
((hass-dash-toggle :entity-id "light.kitchen_lights")
(hass-dash-toggle :entity-id "switch.entry_lights")))))
#+END_SRC
*** Structure To use the dashboard feature, ~hass-dash-layouts~ must be configure to tell ~hass~ what the layout should look like. The layout is constructed with three components: groups, widgets, and properties.
- Each element in ~hass-dash-layouts~ is a dashboard.
- A dashboard is a cons of its key/id and the widgets it contains.
- A widget is an Emacs widget, probably one from this package.
Any widgets defined in ~hass-dash-layouts~ are automatically inserted into the ~hass-tracked-entities~ list in order to receive state updates.
*** Widgets
All widgets contain at least the following properties:
| Widget Property | Description | |---------------------+----------------------------------------------------------------------------------------------| | ~:label~ | The human readable label of the widget to be shown on the dashboard. | | ~:service~ | The service to be called when the widget is selected. | | ~:icon~ | The icon to be shown prefixed to the widget. | | ~:confirm~ | When ~t~ or a string, ask for confirmation before calling the service. |
**** State
A 'state' widget is a read-only widget to simply display the state of some entity. I typically like to use this as the very first widget in a group to show the overall status of the group. For example, a vacuum:
#+BEGIN_SRC emacs-lisp (hass-dash-group :title "Vacuum" (hass-dash-state :entity-id "vacuum.valetudo_vacuum" :format "%v\n") ; Vacuum related widgets ; ... ) #+END_SRC
**** Button
A 'button' widget is a push-button widget to call a service.
#+BEGIN_SRC emacs-lisp (hass-dash-button :entity-id "vacuum.valetudo_vacuum" :service "vacuum.start" :format "%[%t: %v%]\n" :label "Clean") #+END_SRC
**** Toggle
A 'toggle' widget is similar to a button, except it'll only show on or off. If the state is anything other than "on", then it will show "off".
#+BEGIN_SRC emacs-lisp (hass-dash-toggle :entity-id "light.kitchen") #+END_SRC
- Usage
To call a service on Home Assistant, use the ~hass-call-service~ function which has two required arguments: ~entity-id~ and ~service~.
#+BEGIN_SRC emacs-lisp :results none (hass-call-service "switch.bedroom_light" "switch.toggle") #+END_SRC
If you call ~hass-call-service~ interactively, it will prompt you for an entity ID and then the respective service you want to call.
** Dashboard
After configuring the ~hass-dash-layouts~, use the function ~hass-dash-open~ to pop open a dashboard. This can be enhanced with standard buffer management configuration or packages like =popper= and/or =shackle=.
** Payloads
For services that require additional data use the ~hass-call-service-with-payload~ function. The second argument, ~payload~, requires an JSON encoded string.
This example publishes to an MQTT topic:
#+BEGIN_SRC emacs-lisp :results none (hass-call-service-with-payload "mqtt.publish" (json-encode '(("payload" . "PERFORM") ("topic" . "valetudo/vacuum/LocateCapability/locate/set")))) #+END_SRC
You could pass a JSON string directly, but that would require escaping every quote which can be cumbersome. Here's what the encoded list above looks like in JSON:
#+BEGIN_SRC javascript { "payload": "PERFORM", "topic": "valetudo/vacuum/LocateCapability/locate/set" } #+END_SRC
** Hooks
The most useful hook is a function list named ~hass-entity-state-changed-functions~. Functions in this list are passed a single argument ~entity-id~ which is the entity id of the entity whose state has changed since it was last updated. Using this function hook along side [[*Tracking entities][tracking entities]] enables Emacs to react to changes to Home Assistant entities.
This example will display the state of an entity when it changes:
#+BEGIN_SRC emacs-lisp :results none (add-hook 'hass-entity-state-changed-functions (lambda (entity-id) (message "The entity %s state has changed to %s." entity-id (hass-state-of entity-id)))) #+END_SRC
The other two hooks available are ~hass-entity-updated-hook~ and ~hass-service-called-hook~. ~hass-entity-updated-hook~ is called when the state of an entity is updated, regardless of if it changed or not. ~hass-service-called-hook~ is called when a service is called.
#+BEGIN_SRC emacs-lisp :results none (add-hook 'hass-service-called-hook (lambda () (message "A service was called."))) (add-hook 'hass-entity-updated-hook (lambda () (message "An entitys' state was updated."))) #+END_SRC
- License
MIT