{"id":22904471,"url":"https://github.com/gruberdev/extended-hass-llm","last_synced_at":"2025-08-07T23:09:14.543Z","repository":{"id":265797421,"uuid":"869272395","full_name":"gruberdev/extended-hass-llm","owner":"gruberdev","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-08T23:56:49.000Z","size":87,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T05:13:59.191Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gruberdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-08T02:45:22.000Z","updated_at":"2024-10-08T23:56:18.000Z","dependencies_parsed_at":"2024-12-07T20:38:53.706Z","dependency_job_id":null,"html_url":"https://github.com/gruberdev/extended-hass-llm","commit_stats":null,"previous_names":["gruberdev/extended-hass-llm"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruberdev%2Fextended-hass-llm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruberdev%2Fextended-hass-llm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruberdev%2Fextended-hass-llm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruberdev%2Fextended-hass-llm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gruberdev","download_url":"https://codeload.github.com/gruberdev/extended-hass-llm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246605889,"owners_count":20804304,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-14T02:46:26.902Z","updated_at":"2025-04-01T08:27:13.479Z","avatar_url":"https://github.com/gruberdev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Extended HASS LLM\nThis is custom component of Home Assistant.\n\nDerived from [OpenAI Conversation](https://www.home-assistant.io/integrations/openai_conversation/) with some new features such as call-service.\n\n## Additional Features\n- Ability to call service of Home Assistant\n- Ability to create automation\n- Ability to get data from external API or web page\n- Ability to retrieve state history of entities\n- Option to pass the current user's name to OpenAI via the user message context\n\n## How it works\nExtended OpenAI Conversation uses OpenAI API's feature of [function calling](https://platform.openai.com/docs/guides/function-calling) to call service of Home Assistant.\n\nSince \"gpt-3.5-turbo\" model already knows how to call service of Home Assistant in general, you just have to let model know what devices you have by [exposing entities](https://github.com/jekalmin/extended_hass_llm#preparation)\n\n## Installation\n1. Install via registering as a custom repository of HACS or by copying `extended_hass_llm` folder into `\u003cconfig directory\u003e/custom_components`\n2. Restart Home Assistant\n3. Go to Settings \u003e Devices \u0026 Services.\n4. In the bottom right corner, select the Add Integration button.\n5. Follow the instructions on screen to complete the setup (API Key is required).\n    - [Generating an API Key](https://www.home-assistant.io/integrations/openai_conversation/#generate-an-api-key)\n    - Specify \"Base Url\" if using OpenAI compatible servers like LocalAI, otherwise leave as it is.\n6. Go to Settings \u003e [Voice Assistants](https://my.home-assistant.io/redirect/voice_assistants/).\n7. Click to edit Assistant (named \"Home Assistant\" by default).\n8. Select \"Extended OpenAI Conversation\" from \"Conversation agent\" tab.\n    \u003cdetails\u003e\n\n    \u003csummary\u003eguide image\u003c/summary\u003e\n    \u003cimg width=\"500\" alt=\"스크린샷 2023-10-07 오후 6 15 29\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/0849d241-0b82-47f6-9956-fdb82d678aca\"\u003e\n\n    \u003c/details\u003e\n\n## Preparation\nAfter installed, you need to expose entities from \"http://{your-home-assistant}/config/voice-assistants/expose\".\n\n## Examples\n### 1. Turn on single entity\nhttps://github.com/jekalmin/extended_hass_llm/assets/2917984/938dee95-8907-44fd-9fb8-dc8cd559fea2\n\n### 2. Turn on multiple entities\nhttps://github.com/jekalmin/extended_hass_llm/assets/2917984/528f5965-94a7-4cbe-908a-e24f7bbb0a93\n\n### 3. Hook with custom notify function\nhttps://github.com/jekalmin/extended_hass_llm/assets/2917984/4a575ee7-0188-41eb-b2db-6eab61499a99\n\n### 4. Add automation\nhttps://github.com/jekalmin/extended_hass_llm/assets/2917984/04b93aa6-085e-450a-a554-34c1ed1fbb36\n\n### 5. Play Netflix \nhttps://github.com/jekalmin/extended_hass_llm/assets/2917984/64ba656e-3ae7-4003-9956-da71efaf06dc\n\n## Configuration\n### Options\nBy clicking a button from Edit Assist, Options can be customized.\u003cbr/\u003e\nOptions include [OpenAI Conversation](https://www.home-assistant.io/integrations/openai_conversation/) options and two new options. \n\n- `Attach Username`: Pass the active user's name (if applicable) to OpenAI via the message payload. Currently, this only applies to conversations through the UI or REST API.\n\n- `Maximum Function Calls Per Conversation`: limit the number of function calls in a single conversation.\n(Sometimes function is called over and over again, possibly running into infinite loop) \n- `Functions`: A list of mappings of function spec to function.\n  - `spec`: Function which would be passed to [functions](https://platform.openai.com/docs/api-reference/chat/create#chat-create-functions) of [chat API](https://platform.openai.com/docs/api-reference/chat/create).\n  - `function`: function that will be called.\n\n\n| Edit Assist                                                                                                                                  | Options                                                                                                                                                                       |\n|----------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| \u003cimg width=\"608\" alt=\"1\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/bb394cd4-5790-4ac9-9311-dbcab0fcca56\"\u003e | \u003cimg width=\"591\" alt=\"스크린샷 2023-10-10 오후 10 53 57\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/431e4bc5-87a0-4d7b-8da0-6273f955877f\"\u003e |\n\n\n### Functions\n\n#### Supported function types\n- `native`: built-in function provided by \"extended_hass_llm\".\n  - Currently supported native functions and parameters are:\n    - `execute_service`\n      - `domain`(string): domain to be passed to `hass.services.async_call`\n      - `service`(string): service to be passed to `hass.services.async_call`\n      - `service_data`(object): service_data to be passed to `hass.services.async_call`.\n        - `entity_id`(string): target entity\n        - `device_id`(string): target device\n        - `area_id`(string): target area\n    - `add_automation`\n      - `automation_config`(string): An automation configuration in a yaml format\n    - `get_history`\n      - `entity_ids`(list): a list of entity ids to filter\n      - `start_time`(string): defaults to 1 day before the time of the request. It determines the beginning of the period\n      - `end_time`(string): the end of the period in URL encoded format (defaults to 1 day)\n      - `minimal_response`(boolean): only return last_changed and state for states other than the first and last state (defaults to true)\n      - `no_attributes`(boolean): skip returning attributes from the database (defaults to true)\n      - `significant_changes_only`(boolean): only return significant state changes (defaults to true)\n- `script`: A list of services that will be called\n- `template`: The value to be returned from function.\n- `rest`: Getting data from REST API endpoint.\n- `scrape`: Scraping information from website\n- `composite`: A sequence of functions to execute. \n\nBelow is a default configuration of functions.\n\n```yaml\n- spec:\n    name: execute_services\n    description: Use this function to execute service of devices in Home Assistant.\n    parameters:\n      type: object\n      properties:\n        list:\n          type: array\n          items:\n            type: object\n            properties:\n              domain:\n                type: string\n                description: The domain of the service\n              service:\n                type: string\n                description: The service to be called\n              service_data:\n                type: object\n                description: The service data object to indicate what to control.\n                properties:\n                  entity_id:\n                    type: string\n                    description: The entity_id retrieved from available devices. It must start with domain, followed by dot character.\n                required:\n                - entity_id\n            required:\n            - domain\n            - service\n            - service_data\n  function:\n    type: native\n    name: execute_service\n```\n\n## Function Usage\nThis is an example of configuration of functions.\n\nCopy and paste below yaml configuration into \"Functions\".\u003cbr/\u003e\nThen you will be able to let OpenAI call your function. \n\n### 1. template\n#### 1-1. Get current weather\n\nFor real world example, see [weather](https://github.com/jekalmin/extended_hass_llm/tree/main/examples/function/weather).\u003cbr/\u003e\nThis is just an example from [OpenAI documentation](https://platform.openai.com/docs/guides/function-calling/common-use-cases)\n\n```yaml\n- spec:\n    name: get_current_weather\n    description: Get the current weather in a given location\n    parameters:\n      type: object\n      properties:\n        location:\n          type: string\n          description: The city and state, e.g. San Francisco, CA\n        unit:\n          type: string\n          enum:\n          - celcius\n          - farenheit\n      required:\n      - location\n  function:\n    type: template\n    value_template: The temperature in {{ location }} is 25 {{unit}}\n```\n\n\u003cimg width=\"300\" alt=\"스크린샷 2023-10-07 오후 7 56 27\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/05e31ea5-daab-4759-b57d-9f5be546bac8\"\u003e\n\n### 2. script\n#### 2-1. Add item to shopping cart\n```yaml\n- spec:\n    name: add_item_to_shopping_cart\n    description: Add item to shopping cart\n    parameters:\n      type: object\n      properties:\n        item:\n          type: string\n          description: The item to be added to cart\n      required:\n      - item\n  function:\n    type: script\n    sequence:\n    - service: shopping_list.add_item\n      data:\n        name: '{{item}}'\n```\n\n\u003cimg width=\"300\" alt=\"스크린샷 2023-10-07 오후 7 54 56\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/89060728-4703-4e57-8423-354cdc47f0ee\"\u003e\n\n#### 2-2. Send messages to another messenger\n\nIn order to accomplish \"send it to Line\" like [example3](https://github.com/jekalmin/extended_hass_llm#3-hook-with-custom-notify-function), register a notify function like below.\n\n```yaml\n- spec:\n    name: send_message_to_line\n    description: Use this function to send message to Line.\n    parameters:\n      type: object\n      properties:\n        message:\n          type: string\n          description: message you want to send\n      required:\n      - message\n  function:\n    type: script\n    sequence:\n    - service: script.notify_all\n      data:\n        message: \"{{ message }}\"\n```\n\n\u003cimg width=\"300\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/16dc4ca0-c823-4dfe-a2b7-1ba7623acc70\"\u003e\n\n#### 2-3. Get events from calendar\n\nIn order to pass result of calling service to OpenAI, set response variable to `_function_result`. \n\n```yaml\n- spec:\n    name: get_events\n    description: Use this function to get list of calendar events.\n    parameters:\n      type: object\n      properties:\n        start_date_time:\n          type: string\n          description: The start date time in '%Y-%m-%dT%H:%M:%S%z' format\n        end_date_time:\n          type: string\n          description: The end date time in '%Y-%m-%dT%H:%M:%S%z' format\n      required:\n      - start_date_time\n      - end_date_time\n  function:\n    type: script\n    sequence:\n    - service: calendar.get_events\n      data:\n        start_date_time: \"{{start_date_time}}\"\n        end_date_time: \"{{end_date_time}}\"\n      target:\n        entity_id:\n        - calendar.[YourCalendarHere]\n        - calendar.[MoreCalendarsArePossible]\n      response_variable: _function_result\n```\n\n\u003cimg width=\"300\" alt=\"스크린샷 2023-10-31 오후 9 04 56\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/7a6c6925-a53e-4363-a93c-45f63951d41b\"\u003e\n\n#### 2-4. Play Youtube on TV\n\n```yaml\n- spec:\n    name: play_youtube\n    description: Use this function to play Youtube.\n    parameters:\n      type: object\n      properties:\n        video_id:\n          type: string\n          description: The video id.\n      required:\n      - video_id\n  function:\n    type: script\n    sequence:\n    - service: webostv.command\n      data:\n        entity_id: media_player.{YOUR_WEBOSTV}\n        command: system.launcher/launch\n        payload:\n          id: youtube.leanback.v4\n          contentId: \"{{video_id}}\"\n    - delay:\n        hours: 0\n        minutes: 0\n        seconds: 10\n        milliseconds: 0\n    - service: webostv.button\n      data:\n        entity_id: media_player.{YOUR_WEBOSTV}\n        button: ENTER\n```\n\n\u003cimg width=\"300\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/d5c9e0db-8d7c-4a7a-bc46-b043627ffec6\"\u003e\n\n#### 2-5. Play Netflix on TV\n\n```yaml\n- spec:\n    name: play_netflix\n    description: Use this function to play Netflix.\n    parameters:\n      type: object\n      properties:\n        video_id:\n          type: string\n          description: The video id.\n      required:\n      - video_id\n  function:\n    type: script\n    sequence:\n    - service: webostv.command\n      data:\n        entity_id: media_player.{YOUR_WEBOSTV}\n        command: system.launcher/launch\n        payload:\n          id: netflix\n          contentId: \"m=https://www.netflix.com/watch/{{video_id}}\"\n```\n\n\u003cimg width=\"300\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/346065d3-7ab9-49c8-ba30-b79b37a5f084\"\u003e\n\n### 3. native\n\n#### 3-1. Add automation\n\nBefore adding automation, I highly recommend set notification on `automation_registered_via_extended_hass_llm` event and create separate \"Extended OpenAI Assistant\" and \"Assistant\"\n\n(Automation can be added even if conversation fails because of failure to get response message, not automation)\n\n| Create Assistant                                                                                                                             | Notify on created                                                                                                                                                              |\n|----------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| \u003cimg width=\"830\" alt=\"1\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/b7030a46-9a4e-4ea8-a4ed-03d2eb3af0a9\"\u003e | \u003cimg width=\"1116\" alt=\"스크린샷 2023-10-13 오후 6 01 40\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/7afa3709-1c1d-41d0-8847-70f2102d824f\"\u003e |\n\n\nCopy and paste below configuration into \"Functions\"\n\n**For English**\n```yaml\n- spec:\n    name: add_automation\n    description: Use this function to add an automation in Home Assistant.\n    parameters:\n      type: object\n      properties:\n        automation_config:\n          type: string\n          description: A configuration for automation in a valid yaml format. Next line character should be \\n. Use devices from the list.\n      required:\n      - automation_config\n  function:\n    type: native\n    name: add_automation\n```\n\n**For Korean**\n```yaml\n- spec:\n    name: add_automation\n    description: Use this function to add an automation in Home Assistant.\n    parameters:\n      type: object\n      properties:\n        automation_config:\n          type: string\n          description: A configuration for automation in a valid yaml format. Next line character should be \\\\n, not \\n. Use devices from the list.\n      required:\n      - automation_config\n  function:\n    type: native\n    name: add_automation\n```\n\n\u003cimg width=\"300\" alt=\"스크린샷 2023-10-31 오후 9 32 27\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/55f5fe7e-b1fd-43c9-bce6-ac92e203598f\"\u003e\n\n#### 3-2. Get History\nGet state history of entities\n\n```yaml\n- spec:\n    name: get_history\n    description: Retrieve historical data of specified entities.\n    parameters:\n      type: object\n      properties:\n        entity_ids:\n          type: array\n          items:\n            type: string\n            description: The entity id to filter.\n        start_time:\n          type: string\n          description: Start of the history period in \"%Y-%m-%dT%H:%M:%S%z\".\n        end_time:\n          type: string\n          description: End of the history period in \"%Y-%m-%dT%H:%M:%S%z\".\n      required:\n      - entity_ids\n  function:\n    type: composite\n    sequence:\n      - type: native\n        name: get_history\n        response_variable: history_result\n      - type: template\n        value_template: \u003e-\n          {% set ns = namespace(result = [], list = []) %}\n          {% for item_list in history_result %}\n              {% set ns.list = [] %}\n              {% for item in item_list %}\n                  {% set last_changed = item.last_changed | as_timestamp | timestamp_local if item.last_changed else None %}\n                  {% set new_item = dict(item, last_changed=last_changed) %}\n                  {% set ns.list = ns.list + [new_item] %}\n              {% endfor %}\n              {% set ns.result = ns.result + [ns.list] %}\n          {% endfor %}\n          {{ ns.result }}\n```\n\n\u003cimg width=\"300\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/32217f3d-10fc-4001-9028-717b1683573b\"\u003e\n\n### 4. scrape\n#### 4-1. Get current HA version\nScrape version from webpage, \"https://www.home-assistant.io\"\n\nUnlike [scrape](https://www.home-assistant.io/integrations/scrape/), \"value_template\" is added at root level in which scraped data from sensors are passed.\n\n```yaml\n- spec:\n    name: get_ha_version\n    description: Use this function to get Home Assistant version\n    parameters:\n      type: object\n      properties:\n        dummy:\n          type: string\n          description: Nothing\n  function:\n    type: scrape\n    resource: https://www.home-assistant.io\n    value_template: \"version: {{version}}, release_date: {{release_date}}\"\n    sensor:\n      - name: version\n        select: \".current-version h1\"\n        value_template: '{{ value.split(\":\")[1] }}'\n      - name: release_date\n        select: \".release-date\"\n        value_template: '{{ value.lower() }}'\n```\n\n\u003cimg width=\"300\" alt=\"스크린샷 2023-10-31 오후 9 46 07\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/e640c3f3-8d68-486b-818e-bd81bf71c2f7\"\u003e\n\n### 5. rest\n#### 5-1. Get friend names\n- Sample URL: https://jsonplaceholder.typicode.com/users\n```yaml\n- spec:\n    name: get_friend_names\n    description: Use this function to get friend_names\n    parameters:\n      type: object\n      properties:\n        dummy:\n          type: string\n          description: Nothing.\n  function:\n    type: rest\n    resource: https://jsonplaceholder.typicode.com/users\n    value_template: '{{value_json | map(attribute=\"name\") | list }}'\n```\n\n\u003cimg width=\"300\" alt=\"스크린샷 2023-10-31 오후 9 48 36\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/f968e328-5163-4c41-a479-76a5406522c1\"\u003e\n\n\n### 6. composite\n#### 6-1. Search Youtube Music\nWhen using [ytube_music_player](https://github.com/KoljaWindeler/ytube_music_player), after `ytube_music_player.search` service is called, result is stored in attribute of `sensor.ytube_music_player_extra` entity.\u003cbr/\u003e\n\n\n```yaml\n- spec:\n    name: search_music\n    description: Use this function to search music\n    parameters:\n      type: object\n      properties:\n        query:\n          type: string\n          description: The query\n      required:\n      - query\n  function:\n    type: composite\n    sequence:\n    - type: script\n      sequence:\n      - service: ytube_music_player.search\n        data:\n          entity_id: media_player.ytube_music_player\n          query: \"{{ query }}\"\n    - type: template\n      value_template: \u003e-\n        media_content_type,media_content_id,title\n        {% for media in state_attr('sensor.ytube_music_player_extra', 'search') -%}\n          {{media.type}},{{media.id}},{{media.title}}\n        {% endfor%}\n```\n\n\u003cimg width=\"300\" alt=\"스크린샷 2023-11-02 오후 8 40 36\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/648efef8-40d1-45d2-b3f9-9bac4a36c517\"\u003e\n\n### 7. sqlite\n#### 7-1. Let model generate a query\n- Without examples, a query tries to fetch data only from \"states\" table like below\n  \u003e Question: When did bedroom light turn on? \u003cbr/\u003e\n    Query(generated by gpt-3.5): SELECT * FROM states WHERE entity_id = 'input_boolean.livingroom_light_2' AND state = 'on' ORDER BY last_changed DESC LIMIT 1\n- Since \"entity_id\" is stored in \"states_meta\" table, we need to give examples of question and query.\n- Not secured, but flexible way\n\n```yaml\n- spec:\n    name: query_histories_from_db\n    description: \u003e-\n      Use this function to query histories from Home Assistant SQLite database.\n      Example:\n        Question: When did bedroom light turn on?\n        Answer: SELECT datetime(s.last_updated_ts, 'unixepoch', 'localtime') last_updated_ts FROM states s INNER JOIN states_meta sm ON s.metadata_id = sm.metadata_id INNER JOIN states old ON s.old_state_id = old.state_id WHERE sm.entity_id = 'light.bedroom' AND s.state = 'on' AND s.state != old.state ORDER BY s.last_updated_ts DESC LIMIT 1\n        Question: Was livingroom light on at 9 am?\n        Answer: SELECT datetime(s.last_updated_ts, 'unixepoch', 'localtime') last_updated, s.state FROM states s INNER JOIN states_meta sm ON s.metadata_id = sm.metadata_id INNER JOIN states old ON s.old_state_id = old.state_id WHERE sm.entity_id = 'switch.livingroom' AND s.state != old.state AND datetime(s.last_updated_ts, 'unixepoch', 'localtime') \u003c '2023-11-17 08:00:00' ORDER BY s.last_updated_ts DESC LIMIT 1\n    parameters:\n      type: object\n      properties:\n        query:\n          type: string\n          description: A fully formed SQL query.\n  function:\n    type: sqlite\n```\n\nGet last changed date time of state | Get state at specific time\n--|--\n\u003cimg width=\"300\" alt=\"스크린샷 2023-11-19 오후 5 32 56\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/5a25db59-f66c-4dfd-9e7b-ae6982ed3cd2\"\u003e |\u003cimg width=\"300\" alt=\"스크린샷 2023-11-19 오후 5 32 30\" src=\"https://github.com/jekalmin/extended_hass_llm/assets/2917984/51faaa26-3294-4f96-b115-c71b268b708e\"\u003e \n\n\n**FAQ**\n1. Can gpt modify or delete data?\n    \u003e No, since connection is created in a read only mode, data are only used for fetching. \n2. Can gpt query data that are not exposed in database?\n    \u003e Yes, it is hard to validate whether a query is only using exposed entities.\n3. Query uses UTC time. Is there any way to adjust timezone?\n    \u003e Yes. Set \"TZ\" environment variable to your [region](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (eg. `Asia/Seoul`). \u003cbr/\u003e\n      Or use plus/minus hours to adjust instead of 'localtime' (eg. `datetime(s.last_updated_ts, 'unixepoch', '+9 hours')`).\n\n\n#### 7-2. Let model generate a query (with minimum validation)\n- If need to check at least \"entity_id\" of exposed entities is present in a query, use \"is_exposed_entity_in_query\" in combination with \"raise\".\n- Not secured enough, but flexible way\n```yaml\n- spec:\n    name: query_histories_from_db\n    description: \u003e-\n      Use this function to query histories from Home Assistant SQLite database.\n      Example:\n        Question: When did bedroom light turn on?\n        Answer: SELECT datetime(s.last_updated_ts, 'unixepoch', 'localtime') last_updated_ts FROM states s INNER JOIN states_meta sm ON s.metadata_id = sm.metadata_id INNER JOIN states old ON s.old_state_id = old.state_id WHERE sm.entity_id = 'light.bedroom' AND s.state = 'on' AND s.state != old.state ORDER BY s.last_updated_ts DESC LIMIT 1\n        Question: Was livingroom light on at 9 am?\n        Answer: SELECT datetime(s.last_updated_ts, 'unixepoch', 'localtime') last_updated, s.state FROM states s INNER JOIN states_meta sm ON s.metadata_id = sm.metadata_id INNER JOIN states old ON s.old_state_id = old.state_id WHERE sm.entity_id = 'switch.livingroom' AND s.state != old.state AND datetime(s.last_updated_ts, 'unixepoch', 'localtime') \u003c '2023-11-17 08:00:00' ORDER BY s.last_updated_ts DESC LIMIT 1\n    parameters:\n      type: object\n      properties:\n        query:\n          type: string\n          description: A fully formed SQL query.\n  function:\n    type: sqlite\n    query: \u003e-\n      {%- if is_exposed_entity_in_query(query) -%}\n        {{ query }}\n      {%- else -%}\n        {{ raise(\"entity_id should be exposed.\") }}\n      {%- endif -%}\n```\n\n#### 7-3. Defined SQL manually\n- Use a user defined query, which is verified. And model passes a requested entity to get data from database.\n- Secured, but less flexible way\n```yaml\n- spec:\n    name: get_last_updated_time_of_entity\n    description: \u003e\n      Use this function to get last updated time of entity\n    parameters:\n      type: object\n      properties:\n        entity_id:\n          type: string\n          description: The target entity\n  function:\n    type: sqlite\n    query: \u003e-\n      {%- if is_exposed(entity_id) -%}\n        SELECT datetime(s.last_updated_ts, 'unixepoch', 'localtime') as last_updated_ts\n        FROM states s\n          INNER JOIN states_meta sm ON s.metadata_id = sm.metadata_id\n          INNER JOIN states old ON s.old_state_id = old.state_id\n        WHERE sm.entity_id = '{{entity_id}}' AND s.state != old.state ORDER BY s.last_updated_ts DESC LIMIT 1\n      {%- else -%}\n        {{ raise(\"entity_id should be exposed.\") }}\n      {%- endif -%}\n```\n\n## Practical Usage\nSee more practical [examples](https://github.com/jekalmin/extended_hass_llm/tree/main/examples).\n\n## Logging\nIn order to monitor logs of API requests and responses, add following config to `configuration.yaml` file\n\n```yaml\nlogger:\n  logs:\n    custom_components.extended_hass_llm: info\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgruberdev%2Fextended-hass-llm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgruberdev%2Fextended-hass-llm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgruberdev%2Fextended-hass-llm/lists"}