Templating – khuôn mẫu/hình mẫu, là một trong những tính năng nâng cao rất hữu dụng của Home Assistant (Home Assistant). Nội dung bài viết này sẽ làm rõ cách sử dụng Template trong Home Assistant và danh sách thường dùng.
Hiểu đơn giản, templating sẽ giúp bạn “chế biến” thông tin trong Hass, vào Hass và ra khỏi Hass theo ý mình, như:
Di chuyển nhanh: các filter và cấu trúc thường dùng
- Tuỳ chỉnh các thông điệp – message trong thông báo – notification, cả bằng chữ và lời nói
- Trích xuất và thay đổi các thông tin mà Hass nhận được từ nguồn bên ngoài như mqtt, websocket, rest
- Điều khiển tự động hoá – automation thông qua các cấu trúc rẽ nhánh, vòng lặp
- Tuỳ chỉnh giao diện theo thông tin trong Hass hay ngữ cảnh
Cấu trúc thông tin của một entity
Để sử dụng Template hiệu quả, bạn cần nắm được cấu trúc cơ bản của một đối tượng States, chứa thông tin của tất cả các entity trong Home Assistant. Đối tượng States có các attribute
– thuộc tính cơ bản như ảnh trên.
Ví dụ, states của entity home thuộc domain zone bao gồm:
– entity_id: zone.home
– domain: zone
– name (hay friendly_name): my home (tên bạn tuỳ chọn)
– state: zoning (mặc định)
– attributes: [‘hidden’, ‘latitude’, ‘longitude’, ‘radius’, ‘passive’, ‘editable’, ‘friendly_name’, ‘icon’]
– last_changed
– last_updated
Ta có thể truy xuất từng thuộc tính này qua template bằng . (dấu chấm) hay [ ]. Để truy xuất trạng thái – state của một entity, ta dùng cấu trúc states.entity_id.state hoặc state.domain.entity[‘state’] (với một chút khác biệt nhưng không quá quan trọng). Ví dụ, truy xuất trạng thái của entity_id zone.home, ta dùng cấu trúc states.zone.home.state [zone
chính là domain].
Hoặc ta cũng có thể truy xuất state và attributes bằng cấu trúc mở rộng riêng của Home Assistant là states('entity_id')
và state_attr('entity_id','attributes_name')
. Nên sử dụng cấu trúc này nếu được để tránh một số thông báo lỗi khi vì lí do nào đó, states
của các entity_id này chưa có sẵn.
Như vậy:
Để lấy trạng thái của entity zone.home sử dụng Home Assistant template, ta có thể dùng states.zone.home.state
hoặc states.zone.home['state']
hoặc states('zone.home')
(khuyên dùng).
Để lấy dữ liệu icon nằm trong thuộc tính attributes của entity zone.home ta có thể sử dụng states.zone.home.attributes.icon
hoặc states.zone.home.attributes['icon']
hoặc state_attr('zone.home','icon')
(khuyên dùng).
Lưu ý về dấu ‘.‘
Dấu . không chỉ dùng để truy xuất các thuộc tính, nó còn được sử dụng để gọi một phương thức – method của một đối tượng. Bạn cần ghi nhớ điều này để tránh nhầm lẫn.
Làm sao Hass phân biệt được giữa câu từ thông thường và template?
Bằng cả 2 yếu tố:
- Trong hầu hết trường hợp, bạn phải báo trước cho Home Assistant rằng từ thời điểm này, cần sử dụng Templating bằng cách sử dụng từ khoá data_template: hoặc value_template: (tuỳ vào tình huống sử dụng) thay vì data: hoặc value: như bình thường. (cập nhật: từ Home Assistant 0.115, riêng với
data:
vàservice:
templating sẽ được chấp nhận tự động, tức bạn không cần khai báo thêm_template
đằng sau nữa) - Đặt các dấu định nghĩa – delimiters khi muốn Home Assistant thực hiện template. Bao gồm:
–{{ ... }}
khi muốn hiển thị giá trị của biểu thức bên trong. Bạn dùng cấu trúc states(‘zone.home’) để lấy giá trị state của entity zone.home rồi đặt nó bên trong như{{ states('zone.home') }}
để hiển thị.
–{% ... %}
khi muốn thực hiện một câu lệnh, có thể là các cấu trúc điều khiển như if hay for.
Kết hợp 2 điều trên, ta có ví dụ Template kiểu như sau cho ra giá trị ở nhà nếu entity person.me có trạng thái home và vắng nhà từ lúc <thời điểm> khi person.me có bất cứ trạng thái nào mà không phải là home (có thể là away, not_home hay tên một zone nào đó).
<thời điểm> vắng nhà được lấy từ mốc thời gian cuối cùng sensor này chuyển trạng thái. Đây chỉ là ví dụ mẫu nên ta không xử lý tất cả các trường hợp có thể xảy ra mà chỉ lấy tương đối.
value_template: > #dấu '>' để báo hiệu rằng bạn sẽ thể hiện template trên nhiều dòng {% if states('person.me') == 'home' %} ở nhà {% else %} vắng nhà từ lúc {{ states.person.me.last_changed }} {% endif %}
Lưu ý
Trong gần như tất cả các trường hợp, kết quả trả về bởi templating trong Home Assistant sẽ ở dạng chuỗi kí tự – String, bất kể bạn nhìn thấy nó là số, từ điển, danh sách, mảng, hay unknown (không biết), undefined (không xác định) v.v…
Chuỗi kí tự ‘123’ có thể trông chẳng khác gì với số 123 nhưng trong ngôn ngữ máy tính, nó rất khác biệt, như là a và A vậy.
Cập nhật: từ Home Assistant 0.117, công cụ Template đã hỗ trợ các kiểu dữ liệu có sẵn của ngôn ngữ Python như số nguyên, số thập phân, từ điển, danh sách v.v… chứ không còn luôn xuất ra chuỗi kí tự nữa.
Trích dữ liệu đến dạng JSON trong Template
JSON là một dạng cấu trúc dữ liệu mở, đặc trưng bởi cụm key:value
(khoá:dữ liệu). Json được dùng khá phổ biến trong Home Assistant và các dịch vụ bên thứ 3 có liên quan (như Tasmota, các Web API).
Nếu bạn có dữ liệu dạng: {"abc":123,"xyz":"789"}
thì 99% nó là chính là dạng JSON. Bạn có thể kiểm tra một JSON có hợp lệ hay không và xem các key:value
ở dạng đơn thuần bằng trang web này: https://jsonparseronline.com.
Với JSON trên ta có các key “version”, “commit” hay “coordinator”, “log_level” v.v…
Để trích xuất dữ liệu dạng này trong Home Assistant Template, ta sẽ dùng từ khoá value_json thay vì value. Ví dụ để hiển thị data của key “permit_join” ta sẽ dùng cấu trúc: {{ value_json.permit_join }}
. Còn với key mà data lại là dạng JSON (JSON trong JSON) như key “coordinator”, ta sẽ dùng cấu trúc như sau {{ value_json.coordinator.meta.revision }}
để lấy data của key “revision” bên trong data của key “meta” bên trong data của key “coordinator”.
Filter và Format
Nếu bạn có thể lấy thông tin của một entity bằng dấu . thì bạn có thể thay đổi thông tin này bằng các bộ lọc – filter hay bằng cách định dạng – format. Trong Home Assistant Template, để sử dụng các filter, ta đặt filter đằng sau kí tự | (pipe). Ở dưới ta sẽ tìm hiểu rõ hơn về filter.
Các cấu trúc, filter, format, method thông dụng trong Hass
Chung
- {{ states(‘entity_id’) }}
– thể hiện (thường có nghĩa là in ra, đọc ra) ra trạng thái của entity. - {{ state_attr(‘entity_id’,’xyz’ }}
– thể hiện thuộc tính xyz của entity. - {{ is_state(‘entity_id’,’123′) }}
– thể hiện kết quả so sánh state của entity và giá trị ‘123’ (lần nữa bạn cần chú ý đây là chuỗi kí tự). - {{ is_state_attr(‘entity_id’,’xyz’,’123′) }}
– thể hiện kết quả so sánh thuộc tính ‘xyz’ với giá trị ‘123’.
Thời gian
- now()
– trả về thời gian hiện tại theo múi giờ địa phương. - now().hour, now().min, now().second
– trả về giờ, phút, giây hiện tại. - now().year, now().month, now().day
– trả về năm, tháng, ngày hiện tại. - now().weekday()
– trả về ngày trong tuần (CN = 0). - utcnow()
– trả về thời gian theo múi giờ 0. - utcnow().hour, utcnow().min v.v..
– như mục 2, 3 và 4. - as_timestamp(now())
– trả về số giây từ hiện tại lùi về thời điểm 00:00:00 01/01/1970 – Unix Timestamp hay Epoch time (1). - as_timestamp(‘thời gian’)
– như trên nhưng có thể dùng với bất cứ thời gian nào theo chuẩn ISO 8601. - now().strftime(‘%a %A %b %B %d %H %I %m %M %y %Y %j %p %S %U %w %W %z %Z’)
– cần ít nhất một trong các tham số bên trong cặp dấu ‘ ‘, thể hiện một thông số theo thời gian hiện tại (2)
Xem danh sách giải thích ở dưới. - ‘thời gian’.strftime()
– như trên, cho bất cứ thời gian nào theo chuẩn ISO 8601. - strptime(‘thời gian’,’%a %A %b %B %d %H %I %m %M %y %Y %j %p %S %U %w %W %z %Z’)
– chuyển một chuỗi kí tự thành dạng dữ liệu thời gian, ví dụ chuỗi ‘Tuesday 12 May 2020’ được chuyển bởi strptime(‘Tuesday 12 May 2020′,’%A %d %b %Y’).
Ý nghĩa các tham số giống hàm strftime().
%a | thứ rút gọn | %Y | năm dạng đầy đủ |
%A | thứ đầy đủ | %j | ngày trong năm |
%b | tháng rút gọn | %p | AM/PM |
%B | tháng đầy đủ | %S | giây từ 0-61 |
%d | ngày dạng số | %U | tuần trong năm 0-53, CN là đầu tuần |
%H | giờ kiểu 24 | %w | thứ dạng số |
%I | giờ kiểu 12 | %W | tuần trong năm 0-53, T2 là đầu tuần |
%m | tháng dạng số | %z | số giờ bù trừ của múi giờ |
%M | phút | %Z | tên của múi giờ |
%y | 2 số cuối của năm |
Ví dụ sau sẽ in ra giờ, phút và giây hiện tại bằng cả 2 cách khác nhau, và cũng in ra số giây từ lúc entity sun.sun thay đổi lần cuối đến hiện tại:
Giờ: {{now().hour}} Phút: {{now().min}} Giây: {{now().second}} Thời gian hiện tại: {{now().strftime('%H:%M:%S')}} Lần cuối cảm biến thay đổi: {{as_timestamp(now()) - as_timestamp(states.sun.sun.last_changed)}} giây trước
Filter
- int, float
– chuyển sang dạng số nguyên, thập phân - round(x)
– làm tròn đến x số sau dấu thập phân - random()
– lấy ngẫu nhiên - sum(), max(), min()
– lấy tổng, số lớn nhất, số nhỏ nhất - length()
– số kí tự của chuỗi hay số phần tử của một danh sách - upper(), lower(), capitalize()
– viết hoa hết, thường hết hay chỉ viết hoa chữ cái đầu - replace(‘abc’,’xyz’)
– thay tất cả ‘abc’ bằng ‘xyz’ trong chuỗi kí tự - split(‘ab.c.defgh’,’.’)[0]
– chia một chuỗi kí tự thành các phần, phân cách bởi một kí tự (.) rồi lấy phần đầu tiên ([0]) - ‘abcdefgh'[3:5]
– lấy các kí tự từ vị trí 3 đến vị trí 5 của một chuỗi kí tự
Lệnh – statement
- {% if <điều kiện 1> %}
kết quả 1
{% elif <điều kiện 2> %}
kết quả 2
{% else %}
kết quả 3
{% endif %}
Nguyên tắc:
– chỉ có duy nhất 1 if, 1 else và 1 endif
– if và endif là bắt buộc
- {% set var1 = <giá trị> %} – tạo biến var1 có <giá trị> để dùng lặp lại nhiều lần trong cùng 1 template.
- {% for biến in <chuỗi> %} – lặp một vòng từ đầu đến cuối một chuỗi (danh sách)
kết quả
{% endfor %}
Ví dụ, in ra thứ tự và entity_id của tất cả sensor hiện có:
{% for cambien in states.sensor %} {{loop.index}}: {{ cambien.entity_id }} {% endfor %}
Như trên nhưng loại bỏ tất cả dấu xuống dòng cùng khoảng trắng thừa và khi kết thúc vòng lặp, in ra tổng số sensor hiện có:
Lưu ý kí tự ‘–‘
{%- for cambien in states.sensor -%} {{loop.index0}}: {{ cambien.entity_id }} {% if loop.last %}Tổng số: {{loop.length}}{% endif %} {%- endfor -%}
Vẫn còn rất nhiều
Trên đây chỉ là danh sách hay dùng trong Hass, vẫn còn rất nhiều và chúng tôi sẽ cập nhật thêm. Bạn cũng có thể xem ở danh sách tham khảo dưới đây.
Về Bài viết
Bài viết chưa đầy đủ hoặc bạn còn có ý kiến khác? Bạn có thắc mắc và cần thêm thông tin. Vui lòng đăng ý kiến vào mục bình luận để tác giả và Team có thêm thông tin cải thiện chất lượng bài viết. Chúng tôi sẽ giải đáp các thắc mắc ngay trong mục bình luận để giúp được nhiều đọc giả với cùng vấn đề hơn hoặc chúng tôi sẽ trả lời trong một bài viết riêng. Trân trọng cảm ơn bạn!
Cảm ơn bạn đã xem bài viết này!
konnectED Team.