forked from DigiLive/mushroom-strategy
Refactor JavaScript to TypeScript (#81)
Other changes include: * Add Vacuum Card and View. * Add hiding a view if no device is configured for it. Closes #24. * Add icon to HomeView configuration. * Add version output to console. * Add version bumper. * Add .editorconfig settings. * Refactor README, because the information moved to the repository's Wiki. Closes #87.
This commit is contained in:
@ -1,19 +1,19 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
ij_continuation_indent_size = 8
|
||||
ij_continuation_indent_size = 2
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = true
|
||||
ij_smart_tabs = false
|
||||
ij_visual_guides =
|
||||
ij_wrap_on_typing = false
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
tab_width = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[.editorconfig]
|
||||
ij_editorconfig_align_group_field_declarations = false
|
||||
@ -43,7 +43,6 @@ ij_xml_space_inside_empty_tag = false
|
||||
ij_xml_text_wrap = normal
|
||||
|
||||
[{*.ats,*.cts,*.mts,*.ts}]
|
||||
ij_continuation_indent_size = 4
|
||||
ij_typescript_align_imports = false
|
||||
ij_typescript_align_multiline_array_initializer_expression = false
|
||||
ij_typescript_align_multiline_binary_operation = false
|
||||
@ -55,7 +54,7 @@ ij_typescript_align_multiline_parameters_in_calls = false
|
||||
ij_typescript_align_multiline_ternary_operation = false
|
||||
ij_typescript_align_object_properties = 0
|
||||
ij_typescript_align_union_types = false
|
||||
ij_typescript_align_var_statements = 0
|
||||
ij_typescript_align_var_statements = 1
|
||||
ij_typescript_array_initializer_new_line_after_left_brace = false
|
||||
ij_typescript_array_initializer_right_brace_on_new_line = false
|
||||
ij_typescript_array_initializer_wrap = off
|
||||
@ -64,7 +63,7 @@ ij_typescript_binary_operation_sign_on_next_line = false
|
||||
ij_typescript_binary_operation_wrap = off
|
||||
ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
|
||||
ij_typescript_blank_lines_after_imports = 1
|
||||
ij_typescript_blank_lines_around_class = 1
|
||||
ij_typescript_blank_lines_around_class = 0
|
||||
ij_typescript_blank_lines_around_field = 0
|
||||
ij_typescript_blank_lines_around_field_in_interface = 0
|
||||
ij_typescript_blank_lines_around_function = 1
|
||||
@ -112,7 +111,7 @@ ij_typescript_keep_blank_lines_in_code = 2
|
||||
ij_typescript_keep_first_column_comment = true
|
||||
ij_typescript_keep_indents_on_empty_lines = false
|
||||
ij_typescript_keep_line_breaks = true
|
||||
ij_typescript_keep_simple_blocks_in_one_line = false
|
||||
ij_typescript_keep_simple_blocks_in_one_line = true
|
||||
ij_typescript_keep_simple_methods_in_one_line = false
|
||||
ij_typescript_line_comment_add_space = true
|
||||
ij_typescript_line_comment_at_first_column = false
|
||||
@ -132,7 +131,7 @@ ij_typescript_prefer_explicit_types_function_returns = false
|
||||
ij_typescript_prefer_explicit_types_vars_fields = false
|
||||
ij_typescript_prefer_parameters_wrap = false
|
||||
ij_typescript_property_prefix =
|
||||
ij_typescript_reformat_c_style_comments = false
|
||||
ij_typescript_reformat_c_style_comments = true
|
||||
ij_typescript_space_after_colon = true
|
||||
ij_typescript_space_after_comma = true
|
||||
ij_typescript_space_after_dots_in_rest_parameter = false
|
||||
@ -207,6 +206,7 @@ ij_typescript_union_types_wrap = on_every_item
|
||||
ij_typescript_use_chained_calls_group_indents = false
|
||||
ij_typescript_use_double_quotes = true
|
||||
ij_typescript_use_explicit_js_extension = auto
|
||||
ij_typescript_use_import_type = auto
|
||||
ij_typescript_use_path_mapping = always
|
||||
ij_typescript_use_public_modifier = false
|
||||
ij_typescript_use_semicolon_after_statement = true
|
||||
@ -215,20 +215,7 @@ ij_typescript_while_brace_force = never
|
||||
ij_typescript_while_on_new_line = false
|
||||
ij_typescript_wrap_comments = false
|
||||
|
||||
[{*.bash,*.sh,*.zsh}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_shell_binary_ops_start_line = false
|
||||
ij_shell_keep_column_alignment_padding = false
|
||||
ij_shell_minify_program = false
|
||||
ij_shell_redirect_followed_by_space = false
|
||||
ij_shell_switch_cases_indented = false
|
||||
ij_shell_use_unix_line_separator = true
|
||||
|
||||
[{*.cjs,*.js}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_continuation_indent_size = 2
|
||||
ij_javascript_align_imports = false
|
||||
ij_javascript_align_multiline_array_initializer_expression = false
|
||||
ij_javascript_align_multiline_binary_operation = false
|
||||
@ -397,7 +384,6 @@ ij_javascript_while_on_new_line = false
|
||||
ij_javascript_wrap_comments = false
|
||||
|
||||
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.remarkrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
|
||||
indent_size = 2
|
||||
ij_json_array_wrapping = split_into_lines
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
@ -460,7 +446,6 @@ ij_markdown_wrap_text_if_long = true
|
||||
ij_markdown_wrap_text_inside_blockquotes = true
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 2
|
||||
ij_yaml_align_values_properties = do_not_align
|
||||
ij_yaml_autoinsert_sequence_marker = true
|
||||
ij_yaml_block_mapping_on_new_line = false
|
||||
|
19
.github/ISSUE_TEMPLATE/bug_report.md
vendored
19
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -7,27 +7,28 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Versions**
|
||||
**Versions**
|
||||
* Mushroom-Strategy:
|
||||
* HACS:
|
||||
* Mushroom:
|
||||
* Home Assistant:
|
||||
|
||||
**To Reproduce**
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
|
||||
1. Go to '…'
|
||||
2. Click on '…'
|
||||
3. Scroll down to '…'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
10
.github/workflows/webpack.yml
vendored
10
.github/workflows/webpack.yml
vendored
@ -4,7 +4,7 @@ on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
# Ignore changes in folders that are affected by the auto commit. (Node.js project)
|
||||
paths-ignore:
|
||||
paths-ignore:
|
||||
- 'dist/**'
|
||||
# pull_request:
|
||||
# branches: [ "main" ]
|
||||
@ -24,7 +24,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.WORKFLOW_GIT_ACCESS_TOKEN }}
|
||||
token: ${{ secrets.WORKFLOW_GIT_ACCESS_TOKEN }}
|
||||
|
||||
# Build steps
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
- name: Node Install
|
||||
run: npm ci
|
||||
|
||||
|
||||
- name: Build Distribution
|
||||
run: |
|
||||
npm run build
|
||||
@ -44,10 +44,10 @@ jobs:
|
||||
run: |
|
||||
git diff --quiet . || echo "changed=true" >> $GITHUB_OUTPUT
|
||||
|
||||
# Commit and push all changed files.
|
||||
# Commit and push all changed files.
|
||||
# Must only affect files that are listed in "paths-ignore".
|
||||
- name: GIT Commit Distribution Build
|
||||
# Only run on main branch push (e.g. pull request merge).
|
||||
# Only run on main branch push (e.g., pull request merge).
|
||||
if: github.event_name == 'push' && steps.checkDiff.outputs.changed == 'true'
|
||||
run: |
|
||||
git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}"
|
||||
|
@ -3,16 +3,17 @@
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make
|
||||
participation in our project and our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education,
|
||||
socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
participation in our project and our community a harassment-free experience for everyone.
|
||||
This is regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or
|
||||
sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people.
|
||||
* Being respectful of differing opinions, viewpoints and experiences.
|
||||
* Being respectful of differing opinions, viewpoints, and experiences.
|
||||
* Giving and gracefully accepting constructive feedback.
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes and learning from the experience.
|
||||
* Focusing on what is best not just for us as individuals, but for the overall community.
|
||||
@ -28,18 +29,18 @@ Examples of unacceptable behavior include:
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take
|
||||
appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive
|
||||
appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
|
||||
issues and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
issues, and other contributions that are not aligned to this Code of Conduct and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing
|
||||
the community in public spaces. Examples of representing our community include using an official e-mail address, posting
|
||||
via an official social media account or acting as an appointed representative at an online or offline event.
|
||||
via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
@ -80,8 +81,8 @@ enforcing the Code of Conduct, is allowed during this period. Violating these te
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate
|
||||
behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
||||
**Community Impact**: Demonstrating violations of community standards, including sustained inappropriate
|
||||
behavior, harassment of an individual, or aggression toward or disparagement of their class.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
||||
|
||||
|
@ -11,7 +11,7 @@ It will make it a lot easier for us maintainers and smooth out the experience fo
|
||||
The community looks forward to your contributions.
|
||||
|
||||
> And if you like the project, but just don't have time to contribute, that's fine.
|
||||
> There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
|
||||
> There are other easy ways to support the project and show your appreciation, which we would also be thrilled about:
|
||||
> - Star the project
|
||||
> - Tweet about it
|
||||
> - Refer this project in your project's readme
|
||||
@ -58,14 +58,14 @@ We will then take care of the issue as soon as possible.
|
||||
> ### Legal Notice
|
||||
>
|
||||
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the
|
||||
> necessary rights to the content and that the content you contribute may be provided under the project license.
|
||||
> necessary rights to the content, and that the content you contribute may be provided under the project license.
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
#### Before Submitting a Bug Report
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more information.
|
||||
Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report.
|
||||
Therefore, we ask you to investigate carefully, collect information, and describe the issue in detail in your report.
|
||||
Please complete the following steps in advance to help us fix any potential bug as fast as possible.
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
@ -87,7 +87,7 @@ Please complete the following steps in advance to help us fix any potential bug
|
||||
|
||||
#### How Do I Submit a Good Bug Report?
|
||||
|
||||
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue
|
||||
> You must never report security related issues, vulnerabilities, or bugs including sensitive information to the issue
|
||||
> tracker, or elsewhere in public.
|
||||
> Instead, sensitive bugs must be sent by email to <aaliankhan5@gmail.com>.
|
||||
|
||||
|
571
README.md
571
README.md
@ -1,24 +1,28 @@
|
||||
# Mushroom dashboard strategy
|
||||
|
||||
[![hacs][hacsBadge]][hacsUrl]
|
||||
[![release][releaseBadge]][releaseUrl]
|
||||
[![hacs][hacsBadge]][hacsUrl]
|
||||
|
||||

|
||||
|
||||
<details>
|
||||
<summary>More images...</summary>
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
</details>
|
||||
|
||||
## What is Mushroom dashboard strategy?
|
||||
## What is the Mushroom Dashboard Strategy?
|
||||
|
||||
Mushroom dashboard strategy provides a strategy for Home assistant to automatically create a dashboard using Mushroom
|
||||
cards, the area configuration and entity configuration.
|
||||
Mushroom Dashboard Strategy provides a strategy for Home Assistant to automatically generate a dashboard using Mushroom
|
||||
cards.
|
||||
|
||||
My goal is to propose a way to create powerful dashboards without the need of spending hours manually creating them.
|
||||
|
||||
**Note:** This is my first javascript code and GitHub repository. Any recommendations are always welcome.
|
||||
It generates cards for your Home Assistants entities and areas, divided over several views.
|
||||
Besides a Home view from where you can enter a subview of your areas, a separate view for lights, fans and other domains
|
||||
are generated for easy access to your entities.
|
||||
|
||||
### Features
|
||||
|
||||
@ -26,556 +30,53 @@ My goal is to propose a way to create powerful dashboards without the need of sp
|
||||
- 😍 Built-in Views for device-specific controls.
|
||||
- 🎨 Many options to customize to fit your needs.
|
||||
|
||||
## Installation
|
||||
> [!TIP]
|
||||
> If you like this package, please star the [project at GitHub](https://github.com/AalianKhan/mushroom-strategy)! 🌟
|
||||
|
||||
### Prerequisites
|
||||
## Getting started
|
||||
|
||||
You need to install these cards before using this strategy:
|
||||
The strategy is easily installable from [HACS][hacsUrl] (Home Assistant Community Store).
|
||||
Please visit [Installation Guide](https://github.com/AalianKhan/mushroom-strategy/wiki/#installation) at our Wiki.
|
||||
|
||||
- [Mushroom cards][mushroomUrl]
|
||||
- [Mini graph card][mini-graphUrl]
|
||||
## Need some help?
|
||||
|
||||
### HACS
|
||||
Visit the [discussions](https://github.com/AalianKhan/mushroom-strategy/discussions) page.
|
||||
|
||||
Mushroom dashboard strategy is available in [HACS][hacsUrl] (Home Assistant Community Store).
|
||||
## Have an idea or want to report a bug?
|
||||
|
||||
1. Install HACS if you don't have it already.
|
||||
2. Open HACS in Home Assistant.
|
||||
3. Go to the "Frontend" section.
|
||||
4. Click the button with the "+" icon
|
||||
5. Search for "Mushroom dashboard" and install.
|
||||
Make sure your idea or bug isn't discussed already in our Discussions or Issues!
|
||||
Visit the [issues](https://github.com/AalianKhan/mushroom-strategy/issues/new/choose) page.
|
||||
|
||||
### Manual
|
||||
|
||||
1. Download `mushroom-strategy.js` file from
|
||||
the [`dist`](https://github.com/AalianKhan/mushroom-strategy/tree/main/dist) directory.
|
||||
2. Put `mushroom-strategy.js` file into your `config/www` folder.
|
||||
3. Add a reference to `mushroom-strategy.js` in Dashboard.
|
||||
There are two ways to do that:
|
||||
- **Using UI:** _Settings_ → _Dashboards_ → _More Options icon_ → _Resources_ → _Add Resource_ → Set _Url_
|
||||
as `/local/mushroom-strategy.js` → Set _Resource type_ as `JavaScript Module`.
|
||||
**Note:** If you do not see the Resources menu, you will need to enable _Advanced Mode_ in your _User Profile_
|
||||
- **Using YAML:** Add the following code to the `lovelace` section.
|
||||
```yaml
|
||||
resources:
|
||||
- url: /local/mushroom-strategy.js
|
||||
type: module
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
All the rounded cards can be configured using the Dashboard UI editor.
|
||||
|
||||
1. In the UI of the dashboard, click the three dots in the top right corner.
|
||||
2. Click _Edit Dashboard_.
|
||||
3. Click 3 dots again
|
||||
4. Click `Raw configuration editor`
|
||||
5. Add the following lines:
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
views: []
|
||||
```
|
||||
|
||||
### Hidding specific entities
|
||||
|
||||
When creating this dashboard for the first time, you probably have many entities that you don't want to see.
|
||||
|
||||
You can hide these entities by following the steps below:
|
||||
|
||||
1. Click and hold the entity
|
||||
2. Click the `cog icon` in the top right corner of the popup.
|
||||
3. Set `Visible` to `off`.
|
||||
|
||||
The view should update when the page is refreshed.
|
||||
|
||||
If you don't want to hide the entity from all dashboards, you can use [Card Options](#card-options) to hide specific
|
||||
entities and devices.
|
||||
|
||||

|
||||
|
||||
### Adding devices to areas
|
||||
|
||||
You can add devices to an area by going to `Settings` found at the bottom of the sidebar.
|
||||
|
||||
1. Click `Devices and integration`
|
||||
2. Select the integration of your device
|
||||
3. Click the device you wish to add
|
||||
4. Click the `pencil icon` found in the top right corner
|
||||
5. Enter an area in area field.
|
||||
|
||||
You can also set an entity of that device to a different area by going to the advanced settings of that entity.
|
||||
|
||||
If you created an entity in your `configuration.yaml` you may need to enter a `unique_id` first before you set an area
|
||||
to it.
|
||||
See [docs](https://www.home-assistant.io/faq/unique_id/)
|
||||
|
||||
## Strategy options
|
||||
|
||||
You can set strategy options to further customize the dashboard.
|
||||
By default, all views are enabled which include lights, fans, covers, switches, climates and cameras. All chips are also
|
||||
enabled which count the number of devices on for the platforms light, fan, cover and climate. It also auto-selects a
|
||||
weather entity for the weather chip.
|
||||
|
||||
The options available are:
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:---------------------|:--------------------------|:--------------------------------------------------------|:-----------------------------------------------------------------------|
|
||||
| `areas` | object (optional) | unset | One or more areas in a list, see [areas object](#area-object). |
|
||||
| `card_options` | object (optional) | unset | Card options for cards, see [Card Options](#card-options). |
|
||||
| `views` | object (optional) | All default views | See available [Pre-built views](#pre-built-views). |
|
||||
| `chips` | object | All count chips enabled with auto selected weather card | See [chips](#chips). |
|
||||
| `quick_access_cards` | array of cards (optional) | unset | List of cards to show between welcome card and rooms cards. |
|
||||
| `extra_cards` | array of cards (optional | unset | List of cards to show below room cards. |
|
||||
| `extra_views` | array of views (optional) | unset | List of views to add to the dashboard. |
|
||||
| `domains` | object (optional) | All supported domains | See [Supported domains](#supported-domains). |
|
||||
| `homeView` | object (optional) | unset | Options for the home view, see [Home View Options](#home-view-options) |
|
||||
|
||||
#### Example
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
areas:
|
||||
family_room_id:
|
||||
name: Family Room
|
||||
icon: mdi:sofa
|
||||
icon_color: green
|
||||
views: []
|
||||
```
|
||||
|
||||
### Area Object
|
||||
|
||||
The area object includes all options from the template mushroom card and `extra_cards` which is a list of cards to show
|
||||
at the top of the area subview.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------------|:------------------|:---------------|:------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `name` | string | N.A. | The name of the area. |
|
||||
| `icon` | string (optional) | unset or empty | Icon to render. May contain [templates](https://www.home-assistant.io/docs/configuration/templating/). |
|
||||
| `icon_color` | string (optional) | unset or empty | Icon color to render. May contain [templates](https://www.home-assistant.io/docs/configuration/templating/). |
|
||||
| `primary` | string (optional) | unset or empty | Primary info to render. May contain [templates](https://www.home-assistant.io/docs/configuration/templating/). |
|
||||
| `secondary` | string (optional) | unset or empty | Secondary info to render. May contain [templates](https://www.home-assistant.io/docs/configuration/templating/). |
|
||||
| `badge_icon` | string (optional) | unset or empty | Badge icon to render. May contain [templates](https://www.home-assistant.io/docs/configuration/templating/). |
|
||||
| `badge_color` | string (optional) | unset or empty | Badge icon color to render. May contain [templates](https://www.home-assistant.io/docs/configuration/templating/). |
|
||||
| `picture` | string (optional) | unset or empty | Picture to render. May contain [templates](https://www.home-assistant.io/docs/configuration/templating/). |
|
||||
| `multiline_secondary` | boolean | `false` | Enables support for multiline text for the secondary info. |
|
||||
| `layout` | string (optional) | unset or empty | Layout of the card. Vertical, horizontal and default layout are supported. |
|
||||
| `fill_container` | boolean | `false` | Fill container or not. Useful when card is in a grid, vertical or horizontal layout. |
|
||||
| `tap_action` | action* | `none` | Home assistant action to perform on tap. |
|
||||
| `hold_action` | action* | `none` | Home assistant action to perform on hold. |
|
||||
| `entity_id` | `string` `array` | unset or empty | Only reacts to the state changes of these entities. This can be used if the automatic analysis fails to find all relevant entities. |
|
||||
| `double_tap_action` | action* | `more-info` | Home assistant action to perform on double_tap. |
|
||||
| `hidden` | boolean | false | Set to `true` to exclude the area from the dashboard and views. |
|
||||
| `order` | number | Infinity | Ordering position of the area in the list of available areas. |
|
||||
| `extra_cards` | array of cards | unset or empty | A list of cards to show on the top of the area subview. |
|
||||
| `type` | string | `default` | Set to a type of area card. (Currently supported: `default` & `HaAreaCard` |
|
||||
|
||||
*) `more-info` `toggle` `call-service` `navigate` `url` `none`
|
||||
|
||||
#### Example
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
areas:
|
||||
family_room_id:
|
||||
name: Family Room
|
||||
icon: mdi:television
|
||||
icon_color: green
|
||||
order: 1
|
||||
extra_cards:
|
||||
- type: custom:mushroom-chips-card
|
||||
chips:
|
||||
- type: entity
|
||||
entity: sensor.family_room_temperature
|
||||
icon: mdi:thermometer
|
||||
icon_color: pink
|
||||
alignment: center
|
||||
kitchen_id:
|
||||
name: Kitchen
|
||||
icon: mdi:silverware-fork-knife
|
||||
icon_color: red
|
||||
order: 2
|
||||
garage_id:
|
||||
hidden: true
|
||||
hallway_id:
|
||||
type: HaAreaCard
|
||||
views: []
|
||||
```
|
||||
|
||||
#### Undisclosed Area
|
||||
|
||||
The strategy has a special area, named `undisclosed`.
|
||||
This area is enabled by default and includes the entities that aren't linked to any Home Assistant area.
|
||||
|
||||
The area can be configured like any other area as described above.
|
||||
To exclude this area from the dashboard and views, set its property `hidden` to `true`.
|
||||
|
||||
#### Setting options for all areas
|
||||
|
||||
Use `_` as an identifier to set the options for all areas.
|
||||
|
||||
The following example sets the type of all area-cards to Home Assistant's area card:
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
areas:
|
||||
_:
|
||||
type: HaAreaCard
|
||||
views: []
|
||||
```
|
||||
|
||||
### Card Options
|
||||
|
||||
The `card_options` entry enables you to specify a card type for an entity or to hide the card from the dashboard.
|
||||
You can also provide a device ID and hide all entities linked to that device.
|
||||
See [Instructions on to find a device ID](https://community.home-assistant.io/t/device-id-entity-id-where-to-find/289230/4?u=aaliankhan).
|
||||
|
||||
#### Example
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
card_options:
|
||||
fan.master_bedroom_fan:
|
||||
type: custom:mushroom-fan-card
|
||||
remote.harmony_hub_wk:
|
||||
hidden: true
|
||||
077ba0492c9bb3b31ffac34f1f3a626a:
|
||||
hidden: true
|
||||
|
||||
views: []
|
||||
```
|
||||
|
||||
### Pre-built views
|
||||
|
||||

|
||||
|
||||
Mushroom strategy includes pre-built views to control/view specific domains.
|
||||
All devices that are in an area where `hidden` is set to false/undefined are shown*.
|
||||
|
||||
By default, all pre-built views below are shown:
|
||||
|
||||
| Available views | type | Description |
|
||||
|:----------------|:--------|:-----------------------------------------------------------------------------|
|
||||
| `home` | object* | View to show the home screen. |
|
||||
| `light` | object* | View to control all lights and lights of each area. |
|
||||
| `fan` | object* | View to control all fans and fans of each area. |
|
||||
| `cover` | object* | View to control all covers and covers of each area. |
|
||||
| `switch` | object* | View to control all switches and switches of each area. |
|
||||
| `climate` | object* | View to control climate devices such as thermostats. Seperated by each area. |
|
||||
| `camera` | object* | View to show all cameras using WebRTC cards. Seperated by each area. |
|
||||
|
||||
* See [View Options](#view-options).
|
||||
|
||||
#### View Options
|
||||
|
||||
For each of the pre-built views, the following options are available:
|
||||
|
||||
| name | type | description |
|
||||
|:---------|:--------|:----------------------------------------------------------------------------------------------|
|
||||
| `title` | string | Title of the view in the navigation bar. (Shown when no icon is defined or hovering above it. |
|
||||
| `icon` | string | Icon of the view in the navigation bar. |
|
||||
| `order` | string | Ordering position of the view in the navigation bar. |
|
||||
| `hidden` | boolean | Set to `true` to exclude the view from the dashboard |
|
||||
|
||||
#### Example
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
views:
|
||||
light:
|
||||
order: 0
|
||||
title: illumination
|
||||
switch:
|
||||
order: 1
|
||||
hidden: true
|
||||
icon: mdi:toggle-switch
|
||||
views: []
|
||||
```
|
||||
|
||||
### Supported domains
|
||||
|
||||
The following domains are supported and enabled by default:
|
||||
|
||||
* light
|
||||
* fan
|
||||
* cover
|
||||
* switch
|
||||
* camera
|
||||
* lock
|
||||
* climate
|
||||
* media_player
|
||||
* sensor
|
||||
* binary_sensor
|
||||
* number
|
||||
* default (Miscellaneous)
|
||||
|
||||
For these domains, the following options are supported:
|
||||
|
||||
| Option | type | Description |
|
||||
|:---------------|:--------|:--------------------------------------------------------------------------|
|
||||
| `title` | string | Title of the domain in a view. |
|
||||
| `showControls` | boolean | Weather to show controls in a view, to switch all entities of the domain. |
|
||||
| `hidden` | boolean | Set to `true` to exclude the domain from the dashboard. |
|
||||
| `order` | number | Ordering position of the domain entities in a view. |
|
||||
|
||||
#### Example
|
||||
|
||||
```YAML
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
domains:
|
||||
lights:
|
||||
title: "My cool lights"
|
||||
order: 1
|
||||
switch:
|
||||
showControls: false
|
||||
default:
|
||||
hidden: true
|
||||
views: []
|
||||
```
|
||||
|
||||
### Home View Options
|
||||
|
||||
Home View options will let you configure the Home View.
|
||||
|
||||
| Option | type | Description |
|
||||
|:---------|:------|:----------------------------------------------|
|
||||
| `hidden` | array | Array of elements to hide from the home view. |
|
||||
|
||||
#### hidden
|
||||
|
||||
The following elements are supported:
|
||||
* chips
|
||||
* persons
|
||||
* greeting
|
||||
* areasTitle
|
||||
* areas
|
||||
|
||||
#### Example
|
||||
|
||||
```YAML
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
homeView:
|
||||
hidden:
|
||||
- greeting
|
||||
- areasTitle
|
||||
views: []
|
||||
```
|
||||
|
||||
### Chips
|
||||
|
||||

|
||||
|
||||
Mushroom strategy has chips that indicate the number of devices which are active for a specific domain.
|
||||
All devices that are in an area where `hidden` is set to false/undefined are counted.
|
||||
By default, all chips are enabled.
|
||||
|
||||
You can manually configure a weather entity-id to use, and there's also an option to add
|
||||
more [Mushroom Chips][mushroom-chipsUrl] using `extra_chips`.
|
||||
|
||||
**Note: To hide the weather chip, you should hide or disable the entity itself.**
|
||||
|
||||
| Available chips | type | Description |
|
||||
|:-----------------|:------------------|:---------------------------------------------------------------------------------------------------------------|
|
||||
| `light_count` | boolean | Chip to display the number of lights on, tapping turns off all lights, holding navigates to lights view. |
|
||||
| `fan_count` | boolean | Chip to display the number of fans on, tapping turns off all fans, holding navigates to fans view. |
|
||||
| `cover_count` | boolean | Chip to display the number of covers not closed, tapping navigates to covers view. |
|
||||
| `switch_count` | boolean | Chip to display the number of switches on, tapping turns off all switches, holding navigates to switches view. |
|
||||
| `climate_count` | boolean | Chip to display the number of climate not off, tapping navigates to climates view. |
|
||||
| `weather_entity` | string (optional) | Entity ID for the weather chip to use, accepts `weather.` only. |
|
||||
| `extra_chips` | array (optional) | List of extra chips to display, see [Mushroom Chips][mushroom-chipsUrl]. |
|
||||
|
||||
#### Example
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
chips:
|
||||
climate_count: false
|
||||
cover_count: false
|
||||
weather_entity: weather.forecast_home
|
||||
extra_chips:
|
||||
- type: conditional
|
||||
conditions:
|
||||
- entity: lock.front_door
|
||||
state: unlocked
|
||||
chip:
|
||||
type: entity
|
||||
entity: lock.front_door
|
||||
icon_color: red
|
||||
content_info: none
|
||||
tap_action:
|
||||
action: toggle
|
||||
```
|
||||
|
||||
## Full Example
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
type: custom:mushroom-strategy
|
||||
options:
|
||||
views:
|
||||
light:
|
||||
title: illumination
|
||||
switches:
|
||||
hidden: true
|
||||
icon: mdi:toggle-switch
|
||||
homeView:
|
||||
hidden:
|
||||
- Greeting
|
||||
- AreaTitle
|
||||
chips:
|
||||
weather_entity: weather.forecast_home
|
||||
climate_count: false
|
||||
cover_count: false
|
||||
extra_chips:
|
||||
- type: conditional
|
||||
conditions:
|
||||
- entity: lock.front_door
|
||||
state: unlocked
|
||||
chip:
|
||||
type: entity
|
||||
entity: lock.front_door
|
||||
icon_color: red
|
||||
content_info: none
|
||||
icon: ''
|
||||
use_entity_picture: false
|
||||
tap_action:
|
||||
action: toggle
|
||||
- type: conditional
|
||||
conditions:
|
||||
- entity: cover.garage_door
|
||||
state_not: closed
|
||||
chip:
|
||||
type: entity
|
||||
entity: cover.garage_door
|
||||
icon_color: red
|
||||
content_info: none
|
||||
tap_action:
|
||||
action: toggle
|
||||
areas:
|
||||
family_room_id:
|
||||
name: Family Room
|
||||
icon: mdi:television
|
||||
icon_color: green
|
||||
extra_cards:
|
||||
- type: custom:mushroom-chips-card
|
||||
chips:
|
||||
- type: entity
|
||||
entity: sensor.family_room_temperature
|
||||
icon: mdi:thermometer
|
||||
icon_color: pink
|
||||
alignment: center
|
||||
kitchen_id:
|
||||
name: Kitchen
|
||||
icon: mdi:silverware-fork-knife
|
||||
icon_color: red
|
||||
master_bedroom_id:
|
||||
name: Master Bedroom
|
||||
icon: mdi:bed-king
|
||||
icon_color: blue
|
||||
abias_bedroom_id:
|
||||
name: Abia's Bedroom
|
||||
icon: mdi:flower-tulip
|
||||
icon_color: green
|
||||
aalians_bedroom_id:
|
||||
name: Aalian's Bedroom
|
||||
icon: mdi:rocket-launch
|
||||
icon_color: yellow
|
||||
rohaans_bedroom_id:
|
||||
name: Rohaan's Bedroom
|
||||
icon: mdi:controller
|
||||
icon_color: red
|
||||
hallway_id:
|
||||
name: Hallway
|
||||
living_room_id:
|
||||
name: Living Room
|
||||
icon: mdi:sofa
|
||||
front_door_id:
|
||||
name: Front Door
|
||||
icon: mdi:door-closed
|
||||
card_options:
|
||||
fan.master_bedroom_fan:
|
||||
type: custom:mushroom-fan-card
|
||||
remote.harmony_hub_wk:
|
||||
hidden: true
|
||||
quick_access_cards:
|
||||
- type: custom:mushroom-title-card
|
||||
title: Security
|
||||
- type: custom:mushroom-cover-card
|
||||
entity: cover.garage_door
|
||||
show_buttons_control: true
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:mushroom-lock-card
|
||||
entity: lock.front_door
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: sensor.front_door_lock_battery
|
||||
name: Battery
|
||||
extra_cards:
|
||||
- type: custom:xiaomi-vacuum-map-card
|
||||
map_source:
|
||||
camera: camera.xiaomi_cloud_map_extractor
|
||||
calibration_source:
|
||||
camera: true
|
||||
entity: vacuum.robot_vacuum
|
||||
vacuum_platform: default
|
||||
extra_views:
|
||||
- theme: Backend-selected
|
||||
title: cool view
|
||||
path: cool-view
|
||||
icon: mdi:emoticon-cool
|
||||
badges: []
|
||||
cards:
|
||||
- type: markdown
|
||||
content: I am cool
|
||||
views: []
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
* The cards used are from [Mushroom][mushroomUrl], [Mini graph card][mini-graphUrl] and [WebRTC][webRtcUrl]
|
||||
* Took inspiration from [Balloob battery strategy][balloobBatteryUrl]
|
||||
|
||||
## Contributors
|
||||
|
||||
* [DigiLive](https://github.com/DigiLive)
|
||||
|
||||
[![Sponsor DigiLive][sponsorBadge]](https://github.com/sponsors/DigiLive)
|
||||
|
||||
* [Johan Frick](https://github.com/johanfrick)
|
||||
|
||||
<!-- Badges References -->
|
||||
## Credits
|
||||
|
||||
[hacsBadge]: https://img.shields.io/badge/HACS-Default-41BDF5.svg
|
||||
* The cards used are from [Mushroom][mushroomUrl] and [Mini graph card][miniGraphUrl].
|
||||
* Took inspiration from [Balloob battery strategy][balloobBatteryUrl].
|
||||
|
||||
[releaseBadge]: https://img.shields.io/github/v/release/AalianKhan/mushroom-strategy?include_prereleases
|
||||
<!-- Badge References -->
|
||||
|
||||
[hacsBadge]: https://img.shields.io/badge/HACS-Default-blue
|
||||
|
||||
[sponsorBadge]: https://img.shields.io/badge/Sponsor_him-%E2%9D%A4-%23db61a2.svg?&logo=github&color=%23fe8e86
|
||||
|
||||
[releaseBadge]: https://img.shields.io/badge/Release-v2.0.0-blue
|
||||
|
||||
<!-- Other References -->
|
||||
|
||||
[hacsUrl]: https://hacs.xyz
|
||||
|
||||
[releaseUrl]: https://github.com/AalianKhan/mushroom-strategy/releases
|
||||
[releaseUrl]: https://github.com/AalianKhan/mushroom-strategy/releases/tag/v2.0.0
|
||||
|
||||
[mushroomUrl]: https://github.com/piitaya/lovelace-mushroom
|
||||
|
||||
[mushroom-chipsUrl]: https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/chips.md
|
||||
|
||||
[mini-graphUrl]: https://github.com/kalkih/mini-graph-card
|
||||
|
||||
[webRtcUrl]: https://github.com/AlexxIT/WebRTC
|
||||
[miniGraphUrl]: https://github.com/kalkih/mini-graph-card
|
||||
|
||||
[balloobBatteryUrl]: https://gist.github.com/balloob/4a70c83287ddba4e9085cb578ffb161f
|
||||
|
||||
|
2
dist/mushroom-strategy.js
vendored
2
dist/mushroom-strategy.js
vendored
File diff suppressed because one or more lines are too long
3755
package-lock.json
generated
3755
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
@ -1,32 +1,42 @@
|
||||
{
|
||||
"name": "mushroom-strategy",
|
||||
"version": "v1.0.0",
|
||||
"description": "Automatically create a dashboard using Mushroom cards",
|
||||
"keywords": [
|
||||
"strategy",
|
||||
"mushroom"
|
||||
],
|
||||
"homepage": "https://github.com/AalianKhan/mushroom-strategy",
|
||||
"bugs": "https://github.com/AalianKhan/mushroom-strategy/issues",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Aalian Khan"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Ferry Cools"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/AalianKhan/mushroom-strategy"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^5",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"build-dev": "webpack --config webpack.dev.config.js"
|
||||
"name": "mushroom-strategy",
|
||||
"version": "2.0.0",
|
||||
"description": "Automatically create a dashboard using Mushroom cards",
|
||||
"keywords": [
|
||||
"strategy",
|
||||
"mushroom"
|
||||
],
|
||||
"homepage": "https://github.com/AalianKhan/mushroom-strategy",
|
||||
"bugs": "https://github.com/AalianKhan/mushroom-strategy/issues",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Aalian Khan"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Ferry Cools"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/AalianKhan/mushroom-strategy"
|
||||
},
|
||||
"dependencies": {
|
||||
"deepmerge": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"home-assistant-js-websocket": "^9",
|
||||
"superstruct": "^1",
|
||||
"ts-node": "^10",
|
||||
"ts-loader": "^9",
|
||||
"typescript": "^5",
|
||||
"version-bump-prompt": "^6",
|
||||
"webpack": "^5",
|
||||
"webpack-cli": "^5"
|
||||
},
|
||||
"scripts": {
|
||||
"build-dev": "webpack --config webpack.dev.config.ts",
|
||||
"build": "webpack",
|
||||
"bump": "bump -t --preid alpha package.json package-lock.json README.md ./src/mushroom-strategy.ts"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
import {optionDefaults} from "./optionDefaults";
|
||||
import {configurationDefaults} from "./configurationDefaults";
|
||||
import {HassEntities, HassEntity} from "home-assistant-js-websocket";
|
||||
import deepmerge from "deepmerge";
|
||||
import {EntityRegistryEntry} from "./types/homeassistant/data/entity_registry";
|
||||
import {DeviceRegistryEntry} from "./types/homeassistant/data/device_registry";
|
||||
import {AreaRegistryEntry} from "./types/homeassistant/data/area_registry";
|
||||
import {generic} from "./types/strategy/generic";
|
||||
import StrategyArea = generic.StrategyArea;
|
||||
|
||||
/**
|
||||
* Helper Class
|
||||
@ -9,31 +16,34 @@ class Helper {
|
||||
/**
|
||||
* An array of entities from Home Assistant's entity registry.
|
||||
*
|
||||
* @type {hassEntity[]}
|
||||
* @type {EntityRegistryEntry[]}
|
||||
* @private
|
||||
*/
|
||||
static #entities;
|
||||
static #entities: EntityRegistryEntry[];
|
||||
|
||||
/**
|
||||
* An array of entities from Home Assistant's device registry.
|
||||
*
|
||||
* @type {deviceEntity[]}
|
||||
* @type {DeviceRegistryEntry[]}
|
||||
* @private
|
||||
*/
|
||||
static #devices;
|
||||
static #devices: DeviceRegistryEntry[];
|
||||
|
||||
/**
|
||||
* An array of entities from Home Assistant's area registry.
|
||||
*
|
||||
* @type {areaEntity[]}
|
||||
* @type {StrategyArea[]}
|
||||
* @private
|
||||
*/
|
||||
static #areas = [];
|
||||
static #areas: StrategyArea[] = [];
|
||||
|
||||
/**
|
||||
* An array of state entities from Home Assistant's Hass object.
|
||||
*
|
||||
* @type {hassObject["states"]}
|
||||
* @type {HassEntities}
|
||||
* @private
|
||||
*/
|
||||
static #hassStates;
|
||||
static #hassStates: HassEntities;
|
||||
|
||||
/**
|
||||
* Indicates whether this module is initialized.
|
||||
@ -41,27 +51,30 @@ class Helper {
|
||||
* @type {boolean} True if initialized.
|
||||
* @private
|
||||
*/
|
||||
static #initialized = false;
|
||||
static #initialized: boolean = false;
|
||||
|
||||
/**
|
||||
* The Custom strategy configuration.
|
||||
*
|
||||
* @type {customStrategyOptions | {}}
|
||||
* @type {generic.StrategyConfig}
|
||||
* @private
|
||||
*/
|
||||
static #strategyOptions = {};
|
||||
static #strategyOptions: generic.StrategyConfig;
|
||||
|
||||
/**
|
||||
* Set to true for more verbose information in the console.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
static debug = optionDefaults.debug;
|
||||
static #debug: boolean;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* This class shouldn't be instantiated directly. Instead, it should be initialized with method initialize().
|
||||
* This class shouldn't be instantiated directly.
|
||||
* Instead, it should be initialized with method initialize().
|
||||
*
|
||||
* @throws {Error} If trying to instantiate this class.
|
||||
*/
|
||||
constructor() {
|
||||
@ -71,127 +84,115 @@ class Helper {
|
||||
/**
|
||||
* Custom strategy configuration.
|
||||
*
|
||||
* @returns {customStrategyOptions|{}}
|
||||
* @returns {generic.StrategyConfig}
|
||||
* @static
|
||||
*/
|
||||
static get strategyOptions() {
|
||||
static get strategyOptions(): generic.StrategyConfig {
|
||||
return this.#strategyOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {areaEntity[]}
|
||||
* Get the entities from Home Assistant's area registry.
|
||||
*
|
||||
* @returns {StrategyArea[]}
|
||||
* @static
|
||||
*/
|
||||
static get areas() {
|
||||
static get areas(): StrategyArea[] {
|
||||
return this.#areas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {deviceEntity[]}
|
||||
* Get the devices from Home Assistant's device registry.
|
||||
*
|
||||
* @returns {DeviceRegistryEntry[]}
|
||||
* @static
|
||||
*/
|
||||
static get devices() {
|
||||
static get devices(): DeviceRegistryEntry[] {
|
||||
return this.#devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {hassEntity[]}
|
||||
* Get the entities from Home Assistant's entity registry.
|
||||
*
|
||||
* @returns {EntityRegistryEntry[]}
|
||||
* @static
|
||||
*/
|
||||
static get entities() {
|
||||
static get entities(): EntityRegistryEntry[] {
|
||||
return this.#entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current debug mode of the mushroom strategy.
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @static
|
||||
*/
|
||||
static get debug() {
|
||||
return this.debug;
|
||||
static get debug(): boolean {
|
||||
return this.#debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this module.
|
||||
*
|
||||
* @param {dashBoardInfo | viewInfo} info Strategy information object.
|
||||
* @param {generic.DashBoardInfo} info Strategy information object.
|
||||
* @returns {Promise<void>}
|
||||
* @static
|
||||
*/
|
||||
static async initialize(info) {
|
||||
static async initialize(info: generic.DashBoardInfo): Promise<void> {
|
||||
// Initialize properties.
|
||||
this.#hassStates = info.hass.states;
|
||||
this.#strategyOptions = deepmerge(configurationDefaults, info.config?.strategy?.options ?? {});
|
||||
this.#debug = this.#strategyOptions.debug;
|
||||
|
||||
try {
|
||||
// Query the registries of Home Assistant.
|
||||
[this.#entities, this.#devices, this.#areas] = await Promise.all([
|
||||
info.hass.callWS({type: "config/entity_registry/list"}),
|
||||
info.hass.callWS({type: "config/device_registry/list"}),
|
||||
info.hass.callWS({type: "config/area_registry/list"}),
|
||||
|
||||
// noinspection ES6MissingAwait False positive? https://youtrack.jetbrains.com/issue/WEB-63746
|
||||
[Helper.#entities, Helper.#devices, Helper.#areas] = await Promise.all([
|
||||
info.hass.callWS({type: "config/entity_registry/list"}) as Promise<EntityRegistryEntry[]>,
|
||||
info.hass.callWS({type: "config/device_registry/list"}) as Promise<DeviceRegistryEntry[]>,
|
||||
info.hass.callWS({type: "config/area_registry/list"}) as Promise<AreaRegistryEntry[]>,
|
||||
]);
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : "An error occurred while querying Home assistant's registries!");
|
||||
Helper.logError("An error occurred while querying Home assistant's registries!", e);
|
||||
throw 'Check the console for details';
|
||||
}
|
||||
|
||||
// Cloning is required for the purpose of the required undisclosed area.
|
||||
this.#strategyOptions = structuredClone(info.config.strategy.options || {});
|
||||
this.debug = this.#strategyOptions.debug;
|
||||
|
||||
// Setup required configuration entries.
|
||||
// TODO: Refactor to something smarter than repeating code for areas, views and domains.
|
||||
this.#strategyOptions.areas = this.#strategyOptions.areas ?? {};
|
||||
this.#strategyOptions.views = this.#strategyOptions.views ?? {};
|
||||
this.#strategyOptions.domains = this.#strategyOptions.domains ?? {};
|
||||
|
||||
// Setup and add the undisclosed area if not hidden in the strategy options.
|
||||
// Create and add the undisclosed area if not hidden in the strategy options.
|
||||
if (!this.#strategyOptions.areas.undisclosed?.hidden) {
|
||||
this.#strategyOptions.areas.undisclosed = {
|
||||
...optionDefaults.areas.undisclosed,
|
||||
...configurationDefaults.areas.undisclosed,
|
||||
...this.#strategyOptions.areas.undisclosed,
|
||||
};
|
||||
|
||||
// Make sure the area_id of the custom undisclosed area remains null.
|
||||
this.#strategyOptions.areas.undisclosed.area_id = null;
|
||||
// Make sure the custom configuration of the undisclosed area doesn't overwrite the area_id.
|
||||
this.#strategyOptions.areas.undisclosed.area_id = "undisclosed";
|
||||
|
||||
this.#areas.push(this.#strategyOptions.areas.undisclosed);
|
||||
}
|
||||
|
||||
// Merge custom areas of the strategy options into hass areas.
|
||||
// Merge custom areas of the strategy options into strategy areas.
|
||||
this.#areas = Helper.areas.map(area => {
|
||||
return {...area, ...this.#strategyOptions.areas[area.area_id ?? "undisclosed"]};
|
||||
return {...area, ...this.#strategyOptions.areas?.[area.area_id]};
|
||||
});
|
||||
|
||||
// Sort hass areas by order first and then by name.
|
||||
// Sort strategy areas by order first and then by name.
|
||||
this.#areas.sort((a, b) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
// Merge the views of the strategy options and the default views.
|
||||
for (const view of Object.keys(optionDefaults.views)) {
|
||||
this.#strategyOptions.views[view] = {
|
||||
...optionDefaults.views[view],
|
||||
...(this.#strategyOptions.views[view]),
|
||||
};
|
||||
}
|
||||
|
||||
// Sort views of the strategy options by order first and then by title.
|
||||
// Sort custom and default views of the strategy options by order first and then by title.
|
||||
this.#strategyOptions.views = Object.fromEntries(
|
||||
Object.entries(this.#strategyOptions.views).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || a.title?.localeCompare(b.title);
|
||||
}),
|
||||
Object.entries(this.#strategyOptions.views).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || (a.title ?? "undefined").localeCompare(b.title ?? "undefined");
|
||||
}),
|
||||
);
|
||||
|
||||
// Merge the domains of the strategy options and the default domains.
|
||||
for (const domain of Object.keys(optionDefaults.domains)) {
|
||||
this.#strategyOptions.domains[domain] = {
|
||||
...optionDefaults.domains[domain],
|
||||
...(this.#strategyOptions.domains[domain]),
|
||||
};
|
||||
}
|
||||
|
||||
// Sort domains of the strategy options by order first and then by title.
|
||||
// Sort custom and default domains of the strategy options by order first and then by title.
|
||||
this.#strategyOptions.domains = Object.fromEntries(
|
||||
Object.entries(this.#strategyOptions.domains).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || a.title?.localeCompare(b.title);
|
||||
}),
|
||||
Object.entries(this.#strategyOptions.domains).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || (a.title ?? "undefined").localeCompare(b.title ?? "undefined");
|
||||
}),
|
||||
);
|
||||
|
||||
this.#initialized = true;
|
||||
@ -203,7 +204,7 @@ class Helper {
|
||||
* @returns {boolean} True if this module is initialized.
|
||||
* @static
|
||||
*/
|
||||
static isInitialized() {
|
||||
static isInitialized(): boolean {
|
||||
return this.#initialized;
|
||||
}
|
||||
|
||||
@ -219,7 +220,7 @@ class Helper {
|
||||
* @return {string} The template string.
|
||||
* @static
|
||||
*/
|
||||
static getCountTemplate(domain, operator, value) {
|
||||
static getCountTemplate(domain: string, operator: string, value: string): string {
|
||||
// noinspection JSMismatchedCollectionQueryUpdate (False positive per 17-04-2023)
|
||||
/**
|
||||
* Array of entity state-entries, filtered by domain.
|
||||
@ -232,7 +233,7 @@ class Helper {
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
const states = [];
|
||||
const states: string[] = [];
|
||||
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
@ -240,20 +241,20 @@ class Helper {
|
||||
|
||||
// Get the ID of the devices which are linked to the given area.
|
||||
for (const area of this.#areas) {
|
||||
const areaDeviceIds = this.#devices.filter(device => {
|
||||
const areaDeviceIds = this.#devices.filter((device) => {
|
||||
return device.area_id === area.area_id;
|
||||
}).map(device => {
|
||||
}).map((device) => {
|
||||
return device.id;
|
||||
});
|
||||
|
||||
// Get the entities of which all conditions of the callback function are met. @see areaFilterCallback.
|
||||
const newStates = this.#entities.filter(
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.map(entity => `states['${entity.entity_id}']`);
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.map((entity) => `states['${entity.entity_id}']`);
|
||||
|
||||
states.push(...newStates);
|
||||
}
|
||||
@ -261,35 +262,6 @@ class Helper {
|
||||
return `{% set entities = [${states}] %} {{ entities | selectattr('state','${operator}','${value}') | list | count }}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for filtering entities.
|
||||
*
|
||||
* Entities of which all the conditions below are met are kept:
|
||||
* 1. Or/Neither the entity's linked device (if any) or/nor the entity itself is lined to the given area.
|
||||
* (See variable areaMatch)
|
||||
* 2. The entity's domain matches the given domain.
|
||||
* 3. The entity is not hidden and is not disabled.
|
||||
*
|
||||
* @param {hassEntity} entity The current hass entity to evaluate.
|
||||
* @this {areaFilterContext}
|
||||
*
|
||||
* @return {boolean} True to keep the entity.
|
||||
* @static
|
||||
*/
|
||||
static #areaFilterCallback(entity) {
|
||||
const areaMatch = this.area.area_id
|
||||
// Area is a hass entity; The entity's linked device or the entity itself is linked to the given area.
|
||||
? this.areaDeviceIds.includes(entity.device_id) || entity.area_id === this.area.area_id
|
||||
// Undisclosed area; Neither the entity's linked device (if any), nor the entity itself is linked to any area.
|
||||
: (this.areaDeviceIds.includes(entity.device_id) || !entity.device_id) && !entity.area_id;
|
||||
|
||||
return (
|
||||
areaMatch
|
||||
&& entity.entity_id.startsWith(`${this.domain}.`)
|
||||
&& entity.hidden_by == null && entity.disabled_by == null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device entities from the entity registry, filtered by area and domain.
|
||||
*
|
||||
@ -298,36 +270,35 @@ class Helper {
|
||||
*
|
||||
* The result excludes hidden and disabled entities.
|
||||
*
|
||||
* @param {areaEntity} area Area entity.
|
||||
* @param {AreaRegistryEntry} area Area entity.
|
||||
* @param {string} domain The domain of the entity-id.
|
||||
*
|
||||
* @return {hassEntity[]} Array of device entities.
|
||||
* @return {EntityRegistryEntry[]} Array of device entities.
|
||||
* @static
|
||||
*/
|
||||
static getDeviceEntities(area, domain) {
|
||||
static getDeviceEntities(area: AreaRegistryEntry, domain: string): EntityRegistryEntry[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
|
||||
// Get the ID of the devices which are linked to the given area.
|
||||
const areaDeviceIds = this.#devices.filter(device => {
|
||||
return device.area_id === area.area_id;
|
||||
}).map(device => {
|
||||
const areaDeviceIds = this.#devices.filter((device) => {
|
||||
return (device.area_id ?? "undisclosed") === area.area_id;
|
||||
}).map((device: DeviceRegistryEntry) => {
|
||||
|
||||
return device.id;
|
||||
});
|
||||
|
||||
// Return the entities of which all conditions of the callback function are met. @see areaFilterCallback.
|
||||
return this.#entities.filter(
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.sort((a, b) => {
|
||||
/** @type hassEntity */
|
||||
return a.original_name?.localeCompare(b.original_name);
|
||||
});
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return (a.original_name ?? "undefined").localeCompare(b.original_name ?? "undefined");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -335,39 +306,41 @@ class Helper {
|
||||
*
|
||||
* The result excludes hidden and disabled entities.
|
||||
*
|
||||
* @param {areaEntity} area Area entity.
|
||||
* @param {AreaRegistryEntry} area Area entity.
|
||||
* @param {string} domain Domain of the entity-id.
|
||||
*
|
||||
* @return {stateObject[]} Array of state entities.
|
||||
* @return {HassEntity[]} Array of state entities.
|
||||
*/
|
||||
static getStateEntities(area, domain) {
|
||||
static getStateEntities(area: AreaRegistryEntry, domain: string): HassEntity[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
|
||||
const states = [];
|
||||
const states: HassEntity[] = [];
|
||||
|
||||
// Create a map for the hassEntities and devices {id: object} to improve lookup speed.
|
||||
/** @type {Object<string, hassEntity>} */
|
||||
const entityMap = Object.fromEntries(this.#entities.map(entity => [entity.entity_id, entity]));
|
||||
/** @type {Object<string, deviceEntity>} */
|
||||
const deviceMap = Object.fromEntries(this.#devices.map(device => [device.id, device]));
|
||||
const entityMap: {
|
||||
[s: string]: EntityRegistryEntry;
|
||||
} = Object.fromEntries(this.#entities.map((entity) => [entity.entity_id, entity]));
|
||||
const deviceMap: {
|
||||
[s: string]: DeviceRegistryEntry;
|
||||
} = Object.fromEntries(this.#devices.map((device) => [device.id, device]));
|
||||
|
||||
// Get states whose entity-id starts with the given string.
|
||||
const stateEntities = Object.values(this.#hassStates).filter(
|
||||
state => state.entity_id.startsWith(`${domain}.`),
|
||||
(state) => state.entity_id.startsWith(`${domain}.`),
|
||||
);
|
||||
|
||||
for (const state of stateEntities) {
|
||||
const hassEntity = entityMap[state.entity_id];
|
||||
const device = deviceMap[hassEntity?.device_id];
|
||||
const device = deviceMap[hassEntity?.device_id ?? ""];
|
||||
|
||||
// Collect states of which any (whichever comes first) of the conditions below are met:
|
||||
// 1. The linked entity is linked to the given area.
|
||||
// 2. The entity is linked to a device, and the linked device is linked to the given area.
|
||||
if (
|
||||
(hassEntity?.area_id === area.area_id)
|
||||
|| (device && device.area_id === area.area_id)
|
||||
(hassEntity?.area_id === area.area_id)
|
||||
|| (device && device.area_id === area.area_id)
|
||||
) {
|
||||
states.push(state);
|
||||
}
|
||||
@ -385,44 +358,22 @@ class Helper {
|
||||
* @param {string} className Name of the class to sanitize.
|
||||
* @returns {string} The sanitized classname.
|
||||
*/
|
||||
static sanitizeClassName(className) {
|
||||
static sanitizeClassName(className: string): string {
|
||||
className = className.charAt(0).toUpperCase() + className.slice(1);
|
||||
|
||||
return className.replace(/([-_][a-z])/g, group =>
|
||||
group
|
||||
.toUpperCase()
|
||||
.replace("-", "")
|
||||
.replace("_", ""),
|
||||
return className.replace(/([-_][a-z])/g, (group) => group
|
||||
.toUpperCase()
|
||||
.replace("-", "")
|
||||
.replace("_", ""),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys of nested objects by its property value.
|
||||
*
|
||||
* @param {Object<Object>} object An object of objects.
|
||||
* @param {string|number} property The name of the property to evaluate.
|
||||
* @param {*} value The value which the property should match.
|
||||
*
|
||||
* @return {string[]|number[]} An array with keys.
|
||||
*/
|
||||
static #getObjectKeysByPropertyValue(object, property, value) {
|
||||
const keys = [];
|
||||
|
||||
for (const key of Object.keys(object)) {
|
||||
if (object[key][property] === value) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ids of the views which aren't set to hidden in the strategy options.
|
||||
*
|
||||
* @return {string[]} An array of view ids.
|
||||
*/
|
||||
static getExposedViewIds() {
|
||||
static getExposedViewIds(): string[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
@ -435,13 +386,90 @@ class Helper {
|
||||
*
|
||||
* @return {string[]} An array of domain ids.
|
||||
*/
|
||||
static getExposedDomainIds() {
|
||||
static getExposedDomainIds(): string[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
|
||||
return this.#getObjectKeysByPropertyValue(this.#strategyOptions.domains, "hidden", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for filtering entities.
|
||||
*
|
||||
* Entities of which all the conditions below are met are kept:
|
||||
* 1. The entity is not hidden and is not disabled.
|
||||
* 2. The entity's domain matches the given domain.
|
||||
* 3. Or/Neither the entity's linked device (if any) or/nor the entity itself is linked to the given area.
|
||||
* (See variable areaMatch)
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The current hass entity to evaluate.
|
||||
* @this {AreaFilterContext}
|
||||
*
|
||||
* @return {boolean} True to keep the entity.
|
||||
* @static
|
||||
*/
|
||||
static #areaFilterCallback(
|
||||
this: {
|
||||
area: AreaRegistryEntry,
|
||||
areaDeviceIds: string[],
|
||||
domain: string,
|
||||
},
|
||||
entity: EntityRegistryEntry): boolean {
|
||||
const entityUnhidden = entity.hidden_by === null && entity.disabled_by === null;
|
||||
const domainMatches = entity.entity_id.startsWith(`${this.domain}.`);
|
||||
const entityLinked = this.area.area_id === "undisclosed"
|
||||
// Undisclosed area;
|
||||
// nor the entity itself, neither the entity's linked device (if any) is linked to any area.
|
||||
? !entity.area_id && (this.areaDeviceIds.includes(entity.device_id ?? "") || !entity.device_id)
|
||||
// Area is a hass entity;
|
||||
// The entity's linked device or the entity itself is linked to the given area.
|
||||
: this.areaDeviceIds.includes(entity.device_id ?? "") || entity.area_id === this.area.area_id;
|
||||
|
||||
return (entityUnhidden && domainMatches && entityLinked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys of nested objects by its property value.
|
||||
*
|
||||
* @param {Object<string, any>} object An object of objects.
|
||||
* @param {string|number} property The name of the property to evaluate.
|
||||
* @param {*} value The value which the property should match.
|
||||
*
|
||||
* @return {string[]} An array with keys.
|
||||
*/
|
||||
static #getObjectKeysByPropertyValue(
|
||||
object: { [k: string]: any },
|
||||
property: string, value: any
|
||||
): string[] {
|
||||
const keys: string[] = [];
|
||||
|
||||
for (const key of Object.keys(object)) {
|
||||
if (object[key][property] === value) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error message to the console.
|
||||
*
|
||||
* @param {string} userMessage - The error message to display.
|
||||
* @param {unknown} [e] - (Optional) The error object or additional information.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
static logError(userMessage: string, e?: unknown): void {
|
||||
if (Helper.debug) {
|
||||
console.error(userMessage, e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(userMessage);
|
||||
}
|
||||
}
|
||||
|
||||
export {Helper};
|
@ -1,81 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
/**
|
||||
* Abstract Card Class
|
||||
*
|
||||
* To create a new card, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
class AbstractCard {
|
||||
/**
|
||||
* Entity to create the card for.
|
||||
*
|
||||
* @type {hassEntity | areaEntity}
|
||||
*/
|
||||
entity;
|
||||
|
||||
/**
|
||||
* Options for creating a card.
|
||||
*
|
||||
* @type {abstractOptions}
|
||||
*/
|
||||
options = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:help-circle",
|
||||
double_tap_action: {
|
||||
action: null,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity | areaEntity} entity The hass entity to create a card for.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity) {
|
||||
if (this.constructor === AbstractCard) {
|
||||
throw new Error("Abstract classes can't be instantiated.");
|
||||
}
|
||||
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the default options of this class and the custom options into the options of the parent class.
|
||||
*
|
||||
* @param {Object} [defaultOptions={}] Default options for the card.
|
||||
* @param {Object} [customOptions={}] Custom Options for the card.
|
||||
*/
|
||||
mergeOptions(defaultOptions, customOptions) {
|
||||
this.options = {
|
||||
...this.options,
|
||||
...defaultOptions,
|
||||
...customOptions,
|
||||
};
|
||||
|
||||
try {
|
||||
this.options.double_tap_action.target.entity_id = this.entity.entity_id;
|
||||
} catch { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a card for an entity.
|
||||
*
|
||||
* @return {abstractOptions & Object} A card object.
|
||||
*/
|
||||
getCard() {
|
||||
return {
|
||||
entity: this.entity.entity_id,
|
||||
...this.options,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractCard};
|
59
src/cards/AbstractCard.ts
Normal file
59
src/cards/AbstractCard.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {generic} from "../types/strategy/generic";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
/**
|
||||
* Abstract Card Class
|
||||
*
|
||||
* To create a new card, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
abstract class AbstractCard {
|
||||
/**
|
||||
* Entity to create the card for.
|
||||
*
|
||||
* @type {generic.RegistryEntry}
|
||||
*/
|
||||
entity: generic.RegistryEntry;
|
||||
|
||||
/**
|
||||
* Configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
*/
|
||||
config: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:help-circle",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {generic.RegistryEntry} entity The hass entity to create a card for.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
protected constructor(entity: generic.RegistryEntry) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a card.
|
||||
*
|
||||
* @return {cards.AbstractCardConfig} A card object.
|
||||
*/
|
||||
getCard(): cards.AbstractCardConfig {
|
||||
return {
|
||||
...this.config,
|
||||
entity: "entity_id" in this.entity ? this.entity.entity_id : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractCard};
|
@ -1,62 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {areaCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-template-card",
|
||||
primary: undefined,
|
||||
icon: "mdi:texture-box",
|
||||
icon_color: "blue",
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: undefined,
|
||||
},
|
||||
hold_action: {
|
||||
action: "none",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {areaEntity} area The area entity to create a card for.
|
||||
* @param {areaCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(area, options = {}) {
|
||||
super(area);
|
||||
|
||||
this.#defaultOptions.primary = area.name;
|
||||
this.#defaultOptions.tap_action.navigation_path = area.area_id ?? area.name;
|
||||
|
||||
// Set card type to default if a type "default" is given in strategy options.
|
||||
if (options.type === "default") {
|
||||
options.type = this.#defaultOptions.type;
|
||||
}
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
// Override the area's name with a custom name, unless a custom primary text is set.
|
||||
if (!options.primary && options.name) {
|
||||
this.options.primary = options.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
62
src/cards/AreaCard.ts
Normal file
62
src/cards/AreaCard.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {AreaRegistryEntry} from "../types/homeassistant/data/area_registry";
|
||||
import {TemplateCardConfig} from "../types/lovelace-mushroom/cards/template-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {TemplateCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: TemplateCardConfig = {
|
||||
type: "custom:mushroom-template-card",
|
||||
primary: undefined,
|
||||
icon: "mdi:texture-box",
|
||||
icon_color: "blue",
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "",
|
||||
},
|
||||
hold_action: {
|
||||
action: "none",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {AreaRegistryEntry} area The area entity to create a card for.
|
||||
* @param {cards.TemplateCardOptions} [options={}] Options for the card.
|
||||
*
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(area: AreaRegistryEntry, options: cards.TemplateCardOptions = {}) {
|
||||
super(area);
|
||||
|
||||
// Don't override the default card type if default is set in the strategy options.
|
||||
if (options.type === "default") {
|
||||
delete options.type;
|
||||
}
|
||||
|
||||
// Initialize the default configuration.
|
||||
this.#defaultConfig.primary = area.name;
|
||||
if (this.#defaultConfig.tap_action && ("navigation_path" in this.#defaultConfig.tap_action)) {
|
||||
this.#defaultConfig.tap_action.navigation_path = area.area_id;
|
||||
}
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
@ -1,41 +0,0 @@
|
||||
import {SensorCard} from "./SensorCard";
|
||||
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the binary_sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends SensorCard
|
||||
*/
|
||||
class BinarySensorCard extends SensorCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {sensorCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:power-cycle",
|
||||
icon_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {sensorCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {BinarySensorCard};
|
42
src/cards/BinarySensorCard.ts
Normal file
42
src/cards/BinarySensorCard.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import {SensorCard} from "./SensorCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the binary_sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends SensorCard
|
||||
*/
|
||||
class BinarySensorCard extends SensorCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:power-cycle",
|
||||
icon_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.EntityCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.EntityCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {BinarySensorCard};
|
@ -1,41 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Camera Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the camera domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CameraCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {cameraCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
show_state: false,
|
||||
camera_view: "live",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {cameraCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {CameraCard};
|
44
src/cards/CameraCard.ts
Normal file
44
src/cards/CameraCard.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {PictureEntityCardConfig} from "../types/homeassistant/panels/lovelave/cards/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Camera Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the camera domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CameraCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {PictureEntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: PictureEntityCardConfig = {
|
||||
entity: "",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
show_state: false,
|
||||
camera_view: "live",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.PictureEntityCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.PictureEntityCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {CameraCard};
|
@ -1,46 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Climate Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the climate domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class ClimateCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {climateCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-climate-card",
|
||||
icon: undefined,
|
||||
hvac_modes: [
|
||||
"off",
|
||||
"cool",
|
||||
"heat",
|
||||
"fan_only",
|
||||
],
|
||||
show_temperature_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {climateCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateCard};
|
48
src/cards/ClimateCard.ts
Normal file
48
src/cards/ClimateCard.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {ClimateCardConfig} from "../types/lovelace-mushroom/cards/climate-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Climate Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the climate domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class ClimateCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {ClimateCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: ClimateCardConfig = {
|
||||
type: "custom:mushroom-climate-card",
|
||||
icon: undefined,
|
||||
hvac_modes: [
|
||||
"off",
|
||||
"cool",
|
||||
"heat",
|
||||
"fan_only",
|
||||
],
|
||||
show_temperature_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.ClimateCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.ClimateCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateCard};
|
102
src/cards/ControllerCard.ts
Normal file
102
src/cards/ControllerCard.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {StackCardConfig} from "../types/homeassistant/lovelace/cards/types";
|
||||
import {LovelaceCardConfig} from "../types/homeassistant/data/lovelace";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
|
||||
/**
|
||||
* Controller Card class.
|
||||
*
|
||||
* Used for creating a Title Card with controls.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class ControllerCard {
|
||||
/**
|
||||
* @type {HassServiceTarget} The target to control the entities of.
|
||||
* @private
|
||||
*/
|
||||
readonly #target: HassServiceTarget;
|
||||
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {cards.ControllerCardConfig}
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: cards.ControllerCardConfig = {
|
||||
type: "mushroom-title-card",
|
||||
showControls: true,
|
||||
iconOn: "mdi:power-on",
|
||||
iconOff: "mdi:power-off",
|
||||
onService: "none",
|
||||
offService: "none",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {HassServiceTarget} target The target to control the entities of.
|
||||
* @param {cards.ControllerCardOptions} options Controller Card options.
|
||||
*/
|
||||
constructor(target: HassServiceTarget, options: cards.ControllerCardOptions = {}) {
|
||||
this.#target = target;
|
||||
this.#defaultConfig = {
|
||||
...this.#defaultConfig,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Controller card.
|
||||
*
|
||||
* @return {StackCardConfig} A Controller card.
|
||||
*/
|
||||
createCard(): StackCardConfig {
|
||||
const cards: LovelaceCardConfig[] = [
|
||||
{
|
||||
type: "custom:mushroom-title-card",
|
||||
title: this.#defaultConfig.title,
|
||||
subtitle: this.#defaultConfig.subtitle,
|
||||
},
|
||||
];
|
||||
|
||||
if (this.#defaultConfig.showControls) {
|
||||
cards.push({
|
||||
type: "horizontal-stack",
|
||||
cards: [
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#defaultConfig.iconOff,
|
||||
layout: "vertical",
|
||||
icon_color: "red",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#defaultConfig.offService,
|
||||
target: this.#target,
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#defaultConfig.iconOn,
|
||||
layout: "vertical",
|
||||
icon_color: "amber",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#defaultConfig.onService,
|
||||
target: this.#target,
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: "horizontal-stack",
|
||||
cards: cards,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {ControllerCard};
|
@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Cover Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the cover domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CoverCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {coverCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-cover-card",
|
||||
icon: undefined,
|
||||
show_buttons_control: true,
|
||||
show_position_control: true,
|
||||
show_tilt_position_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {coverCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverCard};
|
44
src/cards/CoverCard.ts
Normal file
44
src/cards/CoverCard.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {CoverCardConfig} from "../types/lovelace-mushroom/cards/cover-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Cover Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the cover domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CoverCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {CoverCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: CoverCardConfig = {
|
||||
type: "custom:mushroom-cover-card",
|
||||
icon: undefined,
|
||||
show_buttons_control: true,
|
||||
show_position_control: true,
|
||||
show_tilt_position_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.CoverCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.CoverCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverCard};
|
@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Fan Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the fan domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class FanCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {fanCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-fan-card",
|
||||
icon: undefined,
|
||||
show_percentage_control: true,
|
||||
show_oscillate_control: true,
|
||||
icon_animation: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {fanCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {FanCard};
|
44
src/cards/FanCard.ts
Normal file
44
src/cards/FanCard.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {FanCardConfig} from "../types/lovelace-mushroom/cards/fan-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Fan Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the fan domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class FanCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {FanCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: FanCardConfig = {
|
||||
type: "custom:mushroom-fan-card",
|
||||
icon: undefined,
|
||||
show_percentage_control: true,
|
||||
show_oscillate_control: true,
|
||||
icon_animation: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.FanCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.FanCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {FanCard};
|
@ -1,47 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* HA Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain using the built in type 'area'.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {HaAreaCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "area",
|
||||
area: undefined,
|
||||
navigation_path: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {areaEntity} area The area entity to create a card for.
|
||||
* @param {HaAreaCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
|
||||
constructor(area, options = {}) {
|
||||
super(area);
|
||||
this.#defaultOptions.area = area.area_id ?? area.name;
|
||||
this.#defaultOptions.navigation_path = area.area_id ?? area.name;
|
||||
|
||||
// Enforce the card type.
|
||||
options.type = this.#defaultOptions.type;
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
49
src/cards/HaAreaCard.ts
Normal file
49
src/cards/HaAreaCard.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {AreaRegistryEntry} from "../types/homeassistant/data/area_registry";
|
||||
import {AreaCardConfig} from "../types/homeassistant/lovelace/cards/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* HA Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain using the built-in type 'area'.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {AreaCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: AreaCardConfig = {
|
||||
type: "area",
|
||||
area: "",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {AreaRegistryEntry} area The area entity to create a card for.
|
||||
* @param {cards.AreaCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
|
||||
constructor(area: AreaRegistryEntry, options: cards.AreaCardOptions = {}) {
|
||||
super(area);
|
||||
|
||||
// Initialize the default configuration.
|
||||
this.#defaultConfig.area = area.area_id;
|
||||
this.#defaultConfig.navigation_path = this.#defaultConfig.area;
|
||||
|
||||
// Enforce the card type.
|
||||
delete options.type;
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
@ -1,53 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Light Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the light domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LightCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {lightCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-light-card",
|
||||
icon: undefined,
|
||||
show_brightness_control: true,
|
||||
show_color_control: true,
|
||||
use_light_color: true,
|
||||
show_color_temp_control: true,
|
||||
double_tap_action: {
|
||||
target: {
|
||||
entity_id: undefined,
|
||||
},
|
||||
action: "call-service",
|
||||
service: "light.turn_on",
|
||||
data: {
|
||||
rgb_color: [255, 255, 255],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {lightCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {LightCard};
|
67
src/cards/LightCard.ts
Normal file
67
src/cards/LightCard.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {LightCardConfig} from "../types/lovelace-mushroom/cards/light-card-config";
|
||||
import {generic} from "../types/strategy/generic";
|
||||
import isCallServiceActionConfig = generic.isCallServiceActionConfig;
|
||||
import isCallServiceActionTarget = generic.isCallServiceActionTarget;
|
||||
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Light Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the light domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LightCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {LightCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: LightCardConfig = {
|
||||
type: "custom:mushroom-light-card",
|
||||
icon: undefined,
|
||||
show_brightness_control: true,
|
||||
show_color_control: true,
|
||||
show_color_temp_control: true,
|
||||
use_light_color: true,
|
||||
double_tap_action: {
|
||||
action: "call-service",
|
||||
service: "light.turn_on",
|
||||
target: {
|
||||
entity_id: undefined,
|
||||
},
|
||||
data: {
|
||||
rgb_color: [255, 255, 255],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.LightCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.LightCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
// Set the target for double-tap action.
|
||||
if (
|
||||
isCallServiceActionConfig(this.#defaultConfig.double_tap_action)
|
||||
&& isCallServiceActionTarget(this.#defaultConfig.double_tap_action.target)
|
||||
) {
|
||||
this.#defaultConfig.double_tap_action.target.entity_id = entity.entity_id;
|
||||
}
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {LightCard};
|
@ -1,39 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Lock Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the lock domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LockCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {lockCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-lock-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {lockCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {LockCard};
|
41
src/cards/LockCard.ts
Normal file
41
src/cards/LockCard.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {LockCardConfig} from "../types/lovelace-mushroom/cards/lock-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Lock Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the lock domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LockCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {LockCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: LockCardConfig = {
|
||||
type: "custom:mushroom-lock-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.LockCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.LockCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {LockCard};
|
@ -1,50 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Mediaplayer Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the media_player domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MediaPlayerCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {mediaPlayerCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-media-player-card",
|
||||
icon: undefined,
|
||||
use_media_info: true,
|
||||
media_controls: [
|
||||
"on_off",
|
||||
"play_pause_stop",
|
||||
],
|
||||
show_volume_level: true,
|
||||
volume_controls: [
|
||||
"volume_mute",
|
||||
"volume_set",
|
||||
"volume_buttons",
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {mediaPlayerCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {MediaPlayerCard};
|
51
src/cards/MediaPlayerCard.ts
Normal file
51
src/cards/MediaPlayerCard.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {MediaPlayerCardConfig} from "../types/lovelace-mushroom/cards/media-player-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Mediaplayer Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the media_player domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MediaPlayerCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {MediaPlayerCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: MediaPlayerCardConfig = {
|
||||
type: "custom:mushroom-media-player-card",
|
||||
use_media_info: true,
|
||||
media_controls: [
|
||||
"on_off",
|
||||
"play_pause_stop",
|
||||
],
|
||||
show_volume_level: true,
|
||||
volume_controls: [
|
||||
"volume_mute",
|
||||
"volume_set",
|
||||
"volume_buttons",
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.MediaPlayerCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.MediaPlayerCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {MediaPlayerCard};
|
@ -1,39 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Miscellaneous Card Class
|
||||
*
|
||||
* Used to create a card an entity of any domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MiscellaneousCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {miscellaneousCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon_color: "blue-grey",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {miscellaneousCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {MiscellaneousCard};
|
40
src/cards/MiscellaneousCard.ts
Normal file
40
src/cards/MiscellaneousCard.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
/**
|
||||
* Miscellaneous Card Class
|
||||
*
|
||||
* Used to create a card an entity of any domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MiscellaneousCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon_color: "blue-grey",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.EntityCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.EntityCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {MiscellaneousCard};
|
@ -1,37 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Number Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the number domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class NumberCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {numberCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-number-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {numberCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
|
||||
this.mergeOptions(this.#defaultOptions, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {NumberCard};
|
41
src/cards/NumberCard.ts
Normal file
41
src/cards/NumberCard.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {NumberCardConfig} from "../types/lovelace-mushroom/cards/number-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported
|
||||
/**
|
||||
* Number Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the number domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class NumberCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {NumberCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: NumberCardConfig = {
|
||||
type: "custom:mushroom-number-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.NumberCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.NumberCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {NumberCard};
|
@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Person Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the person domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class PersonCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {personCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-person-card",
|
||||
layout: "vertical",
|
||||
primary_info: "none",
|
||||
secondary_info: "none",
|
||||
icon_type: "entity-picture",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {personCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {PersonCard};
|
43
src/cards/PersonCard.ts
Normal file
43
src/cards/PersonCard.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {PersonCardConfig} from "../types/lovelace-mushroom/cards/person-card-config";
|
||||
|
||||
/**
|
||||
* Person Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the Person domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class PersonCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {PersonCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: PersonCardConfig = {
|
||||
type: "custom:mushroom-person-card",
|
||||
layout: "vertical",
|
||||
primary_info: "none",
|
||||
secondary_info: "none",
|
||||
icon_type: "entity-picture",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.PersonCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.PersonCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {PersonCard};
|
@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SensorCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {sensorCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:information",
|
||||
animate: true,
|
||||
line_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {sensorCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {SensorCard};
|
42
src/cards/SensorCard.ts
Normal file
42
src/cards/SensorCard.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SensorCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:information",
|
||||
animate: true,
|
||||
line_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.EntityCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.EntityCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {SensorCard};
|
@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Switch Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the switch domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SwitchCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {switchCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: undefined,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {switchCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchCard};
|
44
src/cards/SwitchCard.ts
Normal file
44
src/cards/SwitchCard.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Switch Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the switch domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SwitchCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: undefined,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.EntityCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.EntityCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchCard};
|
@ -1,101 +0,0 @@
|
||||
/**
|
||||
* Title Card class.
|
||||
*
|
||||
* Used for creating a Title Card.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class TitleCard {
|
||||
/**
|
||||
* @type {string[]} An array of area ids.
|
||||
* @private
|
||||
*/
|
||||
#areaIds;
|
||||
|
||||
/**
|
||||
* @type {titleCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#options = {
|
||||
title: undefined,
|
||||
subtitle: undefined,
|
||||
showControls: true,
|
||||
iconOn: "mdi:power-on",
|
||||
iconOff: "mdi:power-off",
|
||||
onService: "none",
|
||||
offService: "none",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {areaEntity[]} areas An array of area entities.
|
||||
* @param {titleCardOptions} options Title Card options.
|
||||
*/
|
||||
constructor(areas, options = {}) {
|
||||
this.#areaIds = areas.map(area => area.area_id).filter(area_id => area_id);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Title card.
|
||||
*
|
||||
* @return {Object} A Title card.
|
||||
*/
|
||||
createCard() {
|
||||
/** @type {Object[]} */
|
||||
const cards = [
|
||||
{
|
||||
type: "custom:mushroom-title-card",
|
||||
title: this.#options.title,
|
||||
subtitle: this.#options.subtitle,
|
||||
},
|
||||
];
|
||||
|
||||
if (this.#options.showControls) {
|
||||
cards.push({
|
||||
type: "horizontal-stack",
|
||||
cards: [
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#options.iconOff,
|
||||
layout: "vertical",
|
||||
icon_color: "red",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#options.offService,
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#options.iconOn,
|
||||
layout: "vertical",
|
||||
icon_color: "amber",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#options.onService,
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: "horizontal-stack",
|
||||
cards: cards,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {TitleCard};
|
46
src/cards/VacuumCard.ts
Normal file
46
src/cards/VacuumCard.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {VACUUM_COMMANDS, VacuumCardConfig} from "../types/lovelace-mushroom/cards/vacuum-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Vacuum Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the vacuum domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class VacuumCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {VacuumCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: VacuumCardConfig = {
|
||||
type: "custom:mushroom-vacuum-card",
|
||||
icon: undefined,
|
||||
icon_animation: true,
|
||||
commands: [...VACUUM_COMMANDS],
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.VacuumCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.VacuumCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {VacuumCard};
|
@ -1,154 +0,0 @@
|
||||
/**
|
||||
* @namespace typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} abstractOptions
|
||||
* @property {string} [type] The type of the card.
|
||||
* @property {string} [icon] Icon of the card.
|
||||
* @property {Object} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} titleCardOptions Title Card options.
|
||||
* @property {string} [title] Title to render. May contain templates.
|
||||
* @property {string} [subtitle] Subtitle to render. May contain templates.
|
||||
* @property {boolean} [showControls=true] False to hide controls.
|
||||
* @property {string} [iconOn] Icon to show for switching entities from off state.
|
||||
* @property {string} [iconOff] Icon to show for switching entities to off state.
|
||||
* @property {string} [onService=none] Service to call for switching entities from off state.
|
||||
* @property {string} [offService=none] Service to call for switching entities to off state.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} lightCardOptions Light Card options.
|
||||
* @property {boolean} [show_brightness_control=true] Show a slider to control brightness
|
||||
* @property {boolean} [show_color_control=true] Show a slider to control RGB color
|
||||
* @property {boolean} [use_light_color=true] Colorize the icon and slider according light temperature or color
|
||||
* @property {{double_tap_action: lightDoubleTapAction}} [action] Home assistant action to perform on double_tap
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} lightDoubleTapAction Home assistant action to perform on double_tap.
|
||||
* @property {{entity_id: string}} target The target entity id.
|
||||
* @property {"call-service"} action Calls a hass service.
|
||||
* @property {"light.turn_on"} service The hass service to call
|
||||
* @property {{rgb_color: [255, 255, 255]}} data The data payload for the service.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} coverCardOptions Cover Card options.
|
||||
* @property {boolean} [show_buttons_control=true] Show buttons to open, close and stop cover.
|
||||
* @property {boolean} [show_position_control=true] Show a slider to control position of the cover.
|
||||
* @property {boolean} [show_tilt_position_control=true] Show a slider to control tilt position of the cover.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} fanCardOptions Fan Card options.
|
||||
* @property {boolean} [show_percentage_control=true] Show a slider to control speed.
|
||||
* @property {boolean} [show_oscillate_control=true] Show a button to control oscillation.
|
||||
* @property {boolean} [icon_animation=true] Animate the icon when fan is on.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} lockCardOptions Lock Card options.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} numberCardOptions Number Card options.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} switchCardOptions Switch Card options.
|
||||
* @property {{tap_action: switchTapAction}} [action] Home assistant action to perform on tap.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} switchTapAction Home assistant action to perform on tap.
|
||||
* @property {"toggle"} action Toggles a hass entity.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} climateCardOptions Climate Card options.
|
||||
* @property {["off", "cool", "heat", "fan_only"]} [hvac_modes] Show buttons to control target temperature.
|
||||
* @property {boolean} [show_temperature_control=true] Show buttons to control target temperature.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions} cameraCardOptions Camera Card options.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} personCardOptions Person Card options.
|
||||
* @property {string} [layout] Layout of the card. Vertical, horizontal, and default layouts are supported.
|
||||
* @property {("name" | "state" | "last-changed" | "last-updated" | "none")} [primary_info=name] Info to show as
|
||||
* primary info.
|
||||
* @property {("name" | "state" | "last-changed" | "last-updated" | "none")} [secondary_info=sate] Info to show as
|
||||
* secondary info.
|
||||
* @property {("icon" | "entity-picture" | "none")} [icon_type]=icon Type of icon to display.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} areaCardOptions Area Card options.
|
||||
* @property {string} [name] The name of the area
|
||||
* @property {string} [icon] Icon to render. May contain templates.
|
||||
* @property {string} [icon_color] Icon color to render. May contain templates.
|
||||
* @property {string} [primary] Primary info to render. May contain templates.
|
||||
* @property {areaTapAction} [tap_action] Home assistant action to perform on tap.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} areaTapAction Home assistant action to perform on tap.
|
||||
* @property {"navigate"} action Toggles a hass entity.
|
||||
* @property {string} navigation_path The id of the area to navigate to.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} HaAreaCardOptions HA Area Card options.
|
||||
* @property {string} area The id of the area.
|
||||
* @property {string} navigation_path The id of the area to navigate to.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} mediaPlayerCardOptions Media Player Card options.
|
||||
* @property {boolean} [use_media_info=true] Use media info instead of name, state, and icon when a media is playing
|
||||
* @property {string[]} [media_controls="on_off", "play_pause_stop"] List of controls to display
|
||||
* (on_off, shuffle, previous, play_pause_stop, next,
|
||||
* repeat)
|
||||
* @property {boolean} [show_volume_level=true] Show volume level next to media state when media is playing
|
||||
* @property {string[]} [volume_controls="volume_mute", "volume_set", "volume_buttons"] List of controls to display
|
||||
* (volume_mute, volume_set,
|
||||
* volume_buttons)
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} sensorCardOptions Sensor Card options.
|
||||
* @property {string} [icon_color=green] Custom color for icon when entity is state is active.
|
||||
* @property {boolean} [animate=true] Add a reveal animation to the graph.
|
||||
* @property {string} [line_color=green] Set a custom color for the graph line.
|
||||
* Provide a list of colors for multiple graph entries.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} miscellaneousCardOptions Miscellaneous Card options.
|
||||
* @property {string} [icon_color=blue-grey] Custom color for icon when entity is state is active.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
64
src/chips/AbstractChip.ts
Normal file
64
src/chips/AbstractChip.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
import {LovelaceChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
import {Helper} from "../Helper";
|
||||
import {generic} from "../types/strategy/generic";
|
||||
import isCallServiceActionConfig = generic.isCallServiceActionConfig;
|
||||
|
||||
/**
|
||||
* Abstract Chip class.
|
||||
*
|
||||
* To create a new chip, extend this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
abstract class AbstractChip {
|
||||
/**
|
||||
* Configuration of the chip.
|
||||
*
|
||||
* @type {LovelaceChipConfig}
|
||||
*/
|
||||
config: LovelaceChipConfig = {
|
||||
type: "template"
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*/
|
||||
protected constructor() {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Method is called on dymanically imported classes.
|
||||
/**
|
||||
* Get the chip.
|
||||
*
|
||||
* @returns {LovelaceChipConfig} A chip.
|
||||
*/
|
||||
getChip(): LovelaceChipConfig {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the target to switch.
|
||||
*
|
||||
* @param {HassServiceTarget} target Target to switch.
|
||||
*/
|
||||
setTapActionTarget(target: HassServiceTarget) {
|
||||
if ("tap_action" in this.config && isCallServiceActionConfig(this.config.tap_action)) {
|
||||
this.config.tap_action.target = target;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Helper.debug) {
|
||||
console.warn(
|
||||
this.constructor.name
|
||||
+ " - Target not set: Invalid target or tap action.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractChip};
|
@ -1,39 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class ClimateChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:thermostat",
|
||||
icon_color: "orange",
|
||||
content: Helper.getCountTemplate("climate", "ne", "off"),
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "climates",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "climates",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateChip};
|
47
src/chips/ClimateChip.ts
Normal file
47
src/chips/ClimateChip.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Climate Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many climates are operating.
|
||||
*/
|
||||
class ClimateChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:thermostat",
|
||||
icon_color: "orange",
|
||||
content: Helper.getCountTemplate("climate", "ne", "off"),
|
||||
tap_action: {
|
||||
action: "none",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "climates",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateChip};
|
@ -1,35 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class CoverChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:window-open",
|
||||
icon_color: "cyan",
|
||||
content: Helper.getCountTemplate("cover", "eq", "open"),
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "covers",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverChip};
|
47
src/chips/CoverChip.ts
Normal file
47
src/chips/CoverChip.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Cover Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many covers aren't closed.
|
||||
*/
|
||||
class CoverChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:window-open",
|
||||
icon_color: "cyan",
|
||||
content: Helper.getCountTemplate("cover", "eq", "open"),
|
||||
tap_action: {
|
||||
action: "none",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "covers",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverChip};
|
@ -1,43 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class FanChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:fan",
|
||||
icon_color: "green",
|
||||
content: Helper.getCountTemplate("fan", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "fan.turn_off",
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "fans",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {FanChip};
|
48
src/chips/FanChip.ts
Normal file
48
src/chips/FanChip.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Fan Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many fans are on and to turn all off.
|
||||
*/
|
||||
class FanChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:fan",
|
||||
icon_color: "green",
|
||||
content: Helper.getCountTemplate("fan", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "fan.turn_off",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "fans",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {FanChip};
|
@ -1,43 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class LightChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:lightbulb-group",
|
||||
icon_color: "amber",
|
||||
content: Helper.getCountTemplate("light", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "light.turn_off",
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "lights",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {LightChip};
|
48
src/chips/LightChip.ts
Normal file
48
src/chips/LightChip.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Light Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many lights are on and to turn all off.
|
||||
*/
|
||||
class LightChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:lightbulb-group",
|
||||
icon_color: "amber",
|
||||
content: Helper.getCountTemplate("light", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "light.turn_off",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "lights",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {LightChip};
|
@ -1,43 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class SwitchChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:dip-switch",
|
||||
icon_color: "blue",
|
||||
content: Helper.getCountTemplate("switch", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "switch.turn_off",
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "switches",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchChip};
|
48
src/chips/SwitchChip.ts
Normal file
48
src/chips/SwitchChip.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Switch Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many switches are on and to turn all off.
|
||||
*/
|
||||
class SwitchChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:dip-switch",
|
||||
icon_color: "blue",
|
||||
content: Helper.getCountTemplate("switch", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "switch.turn_off",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "switches",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchChip};
|
@ -1,25 +0,0 @@
|
||||
class WeatherChip {
|
||||
#entityId;
|
||||
#options = {
|
||||
show_temperature: true,
|
||||
show_conditions: true,
|
||||
};
|
||||
|
||||
constructor(entityId, options = {}) {
|
||||
this.#entityId = entityId;
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "weather",
|
||||
entity: this.#entityId,
|
||||
...this.#options,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {WeatherChip};
|
42
src/chips/WeatherChip.ts
Normal file
42
src/chips/WeatherChip.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {WeatherChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols False positive.
|
||||
/**
|
||||
* Weather Chip class.
|
||||
*
|
||||
* Used to create a chip for showing the weather.
|
||||
*/
|
||||
class WeatherChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @private
|
||||
* @readonly
|
||||
*/
|
||||
readonly #defaultConfig: WeatherChipConfig = {
|
||||
type: "weather",
|
||||
show_temperature: true,
|
||||
show_conditions: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {string} entityId Id of a weather entity.
|
||||
* @param {chips.WeatherChipOptions} options Weather Chip options.
|
||||
*/
|
||||
constructor(entityId: string, options: chips.WeatherChipOptions = {}) {
|
||||
super();
|
||||
this.#defaultConfig = {
|
||||
...this.#defaultConfig,
|
||||
...{entity: entityId},
|
||||
...options,
|
||||
};
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {WeatherChip};
|
@ -1,44 +1,20 @@
|
||||
export const optionDefaults = {
|
||||
debug: false,
|
||||
views: {
|
||||
home: {
|
||||
order: 1,
|
||||
hidden: false,
|
||||
},
|
||||
light: {
|
||||
order: 2,
|
||||
hidden: false,
|
||||
},
|
||||
fan: {
|
||||
order: 3,
|
||||
hidden: false,
|
||||
},
|
||||
cover: {
|
||||
order: 4,
|
||||
hidden: false,
|
||||
},
|
||||
switch: {
|
||||
order: 5,
|
||||
hidden: false,
|
||||
},
|
||||
climate: {
|
||||
order: 6,
|
||||
hidden: false,
|
||||
},
|
||||
camera: {
|
||||
order: 7,
|
||||
hidden: false,
|
||||
}
|
||||
},
|
||||
import {generic} from "./types/strategy/generic";
|
||||
import StrategyDefaults = generic.StrategyDefaults;
|
||||
|
||||
/**
|
||||
* Default configuration for the mushroom strategy.
|
||||
*/
|
||||
export const configurationDefaults: StrategyDefaults = {
|
||||
areas: {
|
||||
undisclosed: {
|
||||
aliases: [],
|
||||
area_id: null,
|
||||
area_id: "undisclosed",
|
||||
name: "Undisclosed",
|
||||
picture: null,
|
||||
hidden: false,
|
||||
}
|
||||
},
|
||||
debug: false,
|
||||
domains: {
|
||||
default: {
|
||||
title: "Miscellaneous",
|
||||
@ -116,5 +92,47 @@ export const optionDefaults = {
|
||||
showControls: false,
|
||||
hidden: false,
|
||||
},
|
||||
vacuum: {
|
||||
title: "Vacuums",
|
||||
showControls: true,
|
||||
hidden: false,
|
||||
},
|
||||
},
|
||||
home_view: {
|
||||
hidden: [],
|
||||
},
|
||||
views: {
|
||||
home: {
|
||||
order: 1,
|
||||
hidden: false,
|
||||
},
|
||||
light: {
|
||||
order: 2,
|
||||
hidden: false,
|
||||
},
|
||||
fan: {
|
||||
order: 3,
|
||||
hidden: false,
|
||||
},
|
||||
cover: {
|
||||
order: 4,
|
||||
hidden: false,
|
||||
},
|
||||
switch: {
|
||||
order: 5,
|
||||
hidden: false,
|
||||
},
|
||||
climate: {
|
||||
order: 6,
|
||||
hidden: false,
|
||||
},
|
||||
camera: {
|
||||
order: 7,
|
||||
hidden: false,
|
||||
},
|
||||
vacuum: {
|
||||
order: 8,
|
||||
hidden: false,
|
||||
},
|
||||
}
|
||||
};
|
@ -1,34 +1,40 @@
|
||||
import {Helper} from "./Helper";
|
||||
import {SensorCard} from "./cards/SensorCard";
|
||||
import {TitleCard} from "./cards/TitleCard";
|
||||
import {ControllerCard} from "./cards/ControllerCard";
|
||||
import {generic} from "./types/strategy/generic";
|
||||
import {LovelaceCardConfig, LovelaceConfig, LovelaceViewConfig} from "./types/homeassistant/data/lovelace";
|
||||
import {StackCardConfig} from "./types/homeassistant/lovelace/cards/types";
|
||||
import {EntityCardConfig} from "./types/lovelace-mushroom/cards/entity-card-config";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
import StrategyArea = generic.StrategyArea;
|
||||
|
||||
/**
|
||||
* Mushroom Dashboard Strategy.<br>
|
||||
* <br>
|
||||
* Mushroom dashboard strategy provides a strategy for Home-Assistant to create a dashboard automatically.<br>
|
||||
* The strategy makes use Mushroom, Mini Graph and WebRTC cards to represent your entities.<br>
|
||||
* The strategy makes use Mushroom and Mini Graph cards to represent your entities.<br>
|
||||
* <br>
|
||||
* Features:<br>
|
||||
* 🛠 Automatically create dashboard with 3 lines of yaml.<br>
|
||||
* 🛠 Automatically create dashboard with three lines of yaml.<br>
|
||||
* 😍 Built-in Views for several standard domains.<br>
|
||||
* 🎨 Many options to customize to your needs.<br>
|
||||
* <br>
|
||||
* Check the [Repository]{@link https://github.com/AalianKhan/mushroom-strategy} for more information.
|
||||
*/
|
||||
class MushroomStrategy {
|
||||
class MushroomStrategy extends HTMLTemplateElement {
|
||||
/**
|
||||
* Generate a dashboard.
|
||||
*
|
||||
* Called when opening a dashboard.
|
||||
*
|
||||
* @param {dashBoardInfo} info Dashboard strategy information object.
|
||||
* @return {Promise<{views: Object[]}>}
|
||||
* @param {generic.DashBoardInfo} info Dashboard strategy information object.
|
||||
* @return {Promise<LovelaceConfig>}
|
||||
*/
|
||||
static async generateDashboard(info) {
|
||||
static async generateDashboard(info: generic.DashBoardInfo): Promise<LovelaceConfig> {
|
||||
await Helper.initialize(info);
|
||||
|
||||
// Create views.
|
||||
const views = [];
|
||||
const views: LovelaceViewConfig[] = info.config?.views ?? [];
|
||||
|
||||
let viewModule;
|
||||
|
||||
@ -36,13 +42,14 @@ class MushroomStrategy {
|
||||
for (let viewId of Helper.getExposedViewIds()) {
|
||||
try {
|
||||
const viewType = Helper.sanitizeClassName(viewId + "View");
|
||||
viewModule = await import(`./views/${viewType}`);
|
||||
const view = await new viewModule[viewType](Helper.strategyOptions.views[viewId]).getView();
|
||||
|
||||
views.push(view);
|
||||
viewModule = await import(`./views/${viewType}`);
|
||||
const view: LovelaceViewConfig = await new viewModule[viewType](Helper.strategyOptions.views[viewId]).getView();
|
||||
|
||||
if (view.cards?.length) {
|
||||
views.push(view);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : `View '${viewId}' couldn't be loaded!`);
|
||||
Helper.logError(`View '${viewId}' couldn't be loaded!`, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,13 +86,18 @@ class MushroomStrategy {
|
||||
*
|
||||
* Called when opening a subview.
|
||||
*
|
||||
* @param {viewInfo} info The view's strategy information object.
|
||||
* @return {Promise<{cards: Object[]}>}
|
||||
* @param {generic.ViewInfo} info The view's strategy information object.
|
||||
* @return {Promise<LovelaceViewConfig>}
|
||||
*/
|
||||
static async generateView(info) {
|
||||
static async generateView(info: generic.ViewInfo): Promise<LovelaceViewConfig> {
|
||||
const exposedDomainIds = Helper.getExposedDomainIds();
|
||||
const area = info.view.strategy.options.area;
|
||||
const viewCards = [...(area.extra_cards ?? [])];
|
||||
const area = info.view.strategy?.options?.area ?? {} as StrategyArea;
|
||||
const viewCards: LovelaceCardConfig[] = [...(area.extra_cards ?? [])];
|
||||
|
||||
// Set the target for controller cards to the current area.
|
||||
let target: HassServiceTarget = {
|
||||
area_id: [area.area_id],
|
||||
};
|
||||
|
||||
// Create cards for each domain.
|
||||
for (const domain of exposedDomainIds) {
|
||||
@ -100,27 +112,34 @@ class MushroomStrategy {
|
||||
try {
|
||||
domainCards = await import(`./cards/${className}`).then(cardModule => {
|
||||
let domainCards = [];
|
||||
const entities = Helper.getDeviceEntities(area, domain);
|
||||
const entities = Helper.getDeviceEntities(area, domain);
|
||||
|
||||
// Set the target for controller cards to entities without an area.
|
||||
if (area.area_id === "undisclosed") {
|
||||
target = {
|
||||
entity_id: entities.map(entity => entity.entity_id),
|
||||
}
|
||||
}
|
||||
|
||||
if (entities.length) {
|
||||
// Create a Title card for the current domain.
|
||||
const titleCard = new TitleCard(
|
||||
[area],
|
||||
Helper.strategyOptions.domains[domain],
|
||||
// Create a Controller card for the current domain.
|
||||
const titleCard = new ControllerCard(
|
||||
target,
|
||||
Helper.strategyOptions.domains[domain],
|
||||
).createCard();
|
||||
|
||||
if (domain === "sensor") {
|
||||
// Create a card for each entity-sensor of the current area.
|
||||
const sensorStates = Helper.getStateEntities(area, "sensor");
|
||||
const sensorCards = [];
|
||||
const sensorCards: EntityCardConfig[] = [];
|
||||
|
||||
for (const sensor of entities) {
|
||||
// Find the state of the current sensor.
|
||||
const sensorState = sensorStates.find(state => state.entity_id === sensor.entity_id);
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[sensor.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[sensor.device_id] ?? {};
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[sensor.entity_id];
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[sensor.device_id ?? "null"];
|
||||
|
||||
if (!cardOptions.hidden && !deviceOptions.hidden) {
|
||||
if (!cardOptions?.hidden && !deviceOptions?.hidden) {
|
||||
if (sensorState?.attributes.unit_of_measurement) {
|
||||
cardOptions = {
|
||||
...{
|
||||
@ -147,12 +166,16 @@ class MushroomStrategy {
|
||||
return domainCards;
|
||||
}
|
||||
|
||||
// Create a card for each domain-entity of the current area.
|
||||
// Create a card for each other domain-entity of the current area.
|
||||
for (const entity of entities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id] ?? {};
|
||||
let deviceOptions;
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
|
||||
|
||||
if (!cardOptions.hidden && !deviceOptions.hidden) {
|
||||
if (entity.device_id) {
|
||||
deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id];
|
||||
}
|
||||
|
||||
if (!cardOptions?.hidden && !deviceOptions?.hidden) {
|
||||
domainCards.push(new cardModule[className](entity, cardOptions).getCard());
|
||||
}
|
||||
}
|
||||
@ -179,7 +202,7 @@ class MushroomStrategy {
|
||||
return domainCards;
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : "An error occurred while creating the domain cards!");
|
||||
Helper.logError("An error occurred while creating the domain cards!", e);
|
||||
}
|
||||
|
||||
if (domainCards.length) {
|
||||
@ -193,36 +216,37 @@ class MushroomStrategy {
|
||||
if (!Helper.strategyOptions.domains.default.hidden) {
|
||||
// Create cards for any other domain.
|
||||
// Collect device entities of the current area.
|
||||
const areaDevices = Helper.devices.filter(device => device.area_id === area.area_id)
|
||||
.map(device => device.id);
|
||||
const areaDevices = Helper.devices.filter((device) => device.area_id === area.area_id)
|
||||
.map((device) => device.id);
|
||||
|
||||
// Collect the remaining entities of which all conditions below are met:
|
||||
// 1. The entity is linked to a device which is linked to the current area,
|
||||
// 1. The entity is not hidden.
|
||||
// 2. The entity's domain isn't exposed (entities of exposed domains are already included).
|
||||
// 3. The entity is linked to a device which is linked to the current area,
|
||||
// or the entity itself is linked to the current area.
|
||||
// 2. The entity is not hidden and is not disabled.
|
||||
const miscellaneousEntities = Helper.entities.filter(entity => {
|
||||
return (areaDevices.includes(entity.device_id) || entity.area_id === area.area_id)
|
||||
&& entity.hidden_by == null
|
||||
&& entity.disabled_by == null
|
||||
&& !exposedDomainIds.includes(entity.entity_id.split(".", 1)[0]);
|
||||
const miscellaneousEntities = Helper.entities.filter((entity) => {
|
||||
const entityLinked = areaDevices.includes(entity.device_id ?? "null") || entity.area_id === area.area_id;
|
||||
const entityUnhidden = entity.hidden_by === null && entity.disabled_by === null;
|
||||
const domainExposed = exposedDomainIds.includes(entity.entity_id.split(".", 1)[0]);
|
||||
|
||||
return entityUnhidden && !domainExposed && entityLinked;
|
||||
});
|
||||
|
||||
// Create a column of miscellaneous entity cards.
|
||||
if (miscellaneousEntities.length) {
|
||||
let miscellaneousCards = [];
|
||||
let miscellaneousCards: (StackCardConfig | EntityCardConfig)[] = [];
|
||||
|
||||
try {
|
||||
miscellaneousCards = await import("./cards/MiscellaneousCard").then(cardModule => {
|
||||
/** @type Object[] */
|
||||
const miscellaneousCards = [
|
||||
new TitleCard([area], Helper.strategyOptions.domains.default).createCard(),
|
||||
const miscellaneousCards: (StackCardConfig | EntityCardConfig)[] = [
|
||||
new ControllerCard(target, Helper.strategyOptions.domains.default).createCard(),
|
||||
];
|
||||
|
||||
for (const entity of miscellaneousEntities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id] ?? {};
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id ?? "null"];
|
||||
|
||||
if (!cardOptions.hidden && !deviceOptions.hidden) {
|
||||
if (!cardOptions?.hidden && !deviceOptions?.hidden) {
|
||||
miscellaneousCards.push(new cardModule.MiscellaneousCard(entity, cardOptions).getCard());
|
||||
}
|
||||
}
|
||||
@ -230,7 +254,7 @@ class MushroomStrategy {
|
||||
return miscellaneousCards;
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : "An error occurred while creating the domain cards!");
|
||||
Helper.logError("An error occurred while creating the domain cards!", e);
|
||||
}
|
||||
|
||||
viewCards.push({
|
||||
@ -247,5 +271,10 @@ class MushroomStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnresolvedReference
|
||||
customElements.define("ll-strategy-mushroom-strategy", MushroomStrategy);
|
||||
|
||||
const version = "v2.0.0";
|
||||
console.info(
|
||||
"%c Mushroom Strategy %c ".concat(version, " "),
|
||||
"color: white; background: coral; font-weight: 700;", "color: coral; background: white; font-weight: 700;"
|
||||
);
|
255
src/typedefs.js
255
src/typedefs.js
@ -1,255 +0,0 @@
|
||||
/**
|
||||
* @namespace typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} hassEntity Home assistant entity.
|
||||
* @property {string} name The name of this entity.
|
||||
* @property {string} original_name The original name of this entity.
|
||||
* @property {string} entity_id The id of this entity.
|
||||
* @property {string} device_id The id of the device to which this entity is linked.
|
||||
* @property {string} area_id The id of the area to which this entity is linked.
|
||||
* @property {string[]|null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {string[]|null} hidden_by Indicates by what this entity is hidden.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} deviceEntity Device Entity.
|
||||
* @property {string} area_id The Area which the device is placed in.
|
||||
* @property {string} id Unique ID of a device (generated by Home Assistant).
|
||||
* @property {string[]|null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {string[]|null} hidden_by Indicates by what this entity is hidden.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} areaEntity Area Entity.
|
||||
* @property {string[]} [aliases] Array of aliases of this entity.
|
||||
* @property {string|null} area_id The id of this entity.
|
||||
* @property {string} name Name of this entity.
|
||||
* @property {string|null} picture URL to a picture that should be used instead of showing the domain icon.
|
||||
* @property {number} [order] Ordering position of the area in the list of available areas.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* This property is added by the custom strategy.
|
||||
* @property {Object[]} [extra_cards] An array of card configurations.
|
||||
* The configured cards are added to the dashboard.
|
||||
* This property is added by the custom strategy.
|
||||
* @property {boolean} [use_ha_area_card] Set to true to use ha area card instead of mushroom.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} viewEntity View Entity.
|
||||
* This entity is added by the custom strategy.
|
||||
* @property {string} title Title of this entity.
|
||||
* @property {string} icon Icon to use for the entity in the frontend.
|
||||
* Example: `mdi:home`.
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object & titleCardOptions} domainEntity Domain Entity.
|
||||
* This entity is added by the custom strategy.
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} titleCardOptions Title Card options.
|
||||
* @property {string} [title] Title to render. May contain templates.
|
||||
* @property {string} [subtitle] Subtitle to render. May contain templates.
|
||||
* @property {boolean} [showControls=true] False to hide controls.
|
||||
* @property {string} [iconOn] Icon to show for switching entities from off state.
|
||||
* @property {string} [iconOff] Icon to show for switching entities to off state.
|
||||
* @property {string} [onService=none] Service to call for switching entities from off state.
|
||||
* @property {string} [offService=none] Service to call for switching entities to off state.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} dashBoardInfo Strategy information object.
|
||||
* @property {dashboardConfig} config User supplied dashboard configuration, if any.
|
||||
* @property {hassObject} hass The Home Assistant object.
|
||||
* @property {boolean} narrow If the current user interface is rendered in narrow mode or not.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#dashboard-strategies
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} viewInfo Strategy information object.
|
||||
* @property {Object} view Configuration of the current view.
|
||||
* @property {viewConfig} config Dashboard configuration.
|
||||
* @property {hassObject} hass The Home Assistant object.
|
||||
* @property {boolean} narrow If the current user interface is rendered in narrow mode or not.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#view-strategies
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} dashboardConfig User supplied dashboard configuration.
|
||||
* @property {strategyObject} strategy User supplied dashboard configuration.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} viewConfig Dashboard configuration.
|
||||
* @property {Object[]} strategy Array of views generated by the strategy.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} strategyObject User supplied dashboard configuration.
|
||||
* @property {strategyOptions} options Custom strategy configuration.
|
||||
* @property {string} type Strategy type.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} customStrategyOptions Custom strategy configuration.
|
||||
* @property {boolean} [debug] Set to true for more verbose debugging info.
|
||||
* @property {Object.<areaEntity>} [areas] List of areas.
|
||||
* @property {Object.<cardOptions>} [card_options] Card options for entities.
|
||||
* @property {Object.<viewEntity>} [views] List of views.
|
||||
* @property {Object.<domainEntity>} [domains] List of domains.
|
||||
* @property {chip[]} [chips] List of chips to show in the Home view.
|
||||
* @property {Object[]} [quick_access_cards] List of cards to show between welcome card and rooms cards.
|
||||
* @property {Object[]} [extra_cards] List of cards to show below room cards.
|
||||
* @property {Object[]} [extra_views] List of views to add to the dashboard.
|
||||
* @property {Object.<homeViewOptions>} [homeView] Options for the home view.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} chip List of chips to show in the Home view.
|
||||
* @property {boolean} light_count Chip to display the number of lights on.
|
||||
* @property {boolean} fan_count Chip to display the number of fans on.
|
||||
* @property {boolean} cover_count Chip to display the number of unclosed covers.
|
||||
* @property {boolean} switch_count Chip to display the number of switches on.
|
||||
* @property {boolean} climate_count Chip to display the number of climates which are not off.
|
||||
* @property {string} weather_entity Entity ID for the weather chip to use, accepts `weather.` only.
|
||||
* @property {Object[]} extra_chips List of extra chips.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} homeViewOptions Options for the home view.
|
||||
* @property {string[]} [hidden] Elements to hide from the home view.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} cardOptions Custom card-configuration for an entity.
|
||||
* @property {string} type Type of card for the entity
|
||||
* @property {boolean} hidden True if the entity should be hidden from the dashboard.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* The frontend passes a single hass object around.
|
||||
* This object contains the latest state and allows you to send commands back to the server.
|
||||
*
|
||||
* @typedef {Object} hassObject Home Assistant object.
|
||||
* @property {Object<string, stateObject>} states An object containing the states of all entities in Home Assistant.
|
||||
* The key is the entity_id, the value is the state object.
|
||||
* @property {hassUser} user The logged-in user.
|
||||
* @property {function} callWS Call a WebSocket command on the backend.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/data/
|
||||
*/
|
||||
|
||||
/**
|
||||
* The logged-in user.
|
||||
*
|
||||
* @typedef {Object} hassUser The logged-in user.
|
||||
* @property {string} name Name of the user.
|
||||
* @property {boolean} is_owner True if the user is the owner.
|
||||
* @property {boolean} is_owner True if the user is an administrator.
|
||||
* @property {Object[]} credentials Authentication credentials.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/data/#hassuser
|
||||
*/
|
||||
|
||||
/**
|
||||
* States are a current representation of the entity.
|
||||
*
|
||||
* All states will always have an entity id, a state and a timestamp when last updated and last changed.
|
||||
*
|
||||
* @typedef {Object} stateObject State object.
|
||||
* @property {string} state String representation of the entity's current state.
|
||||
* Example `off`.
|
||||
* @property {string} entity_id Entity ID.
|
||||
* Format: <domain>.<object_id>.
|
||||
* Example: `light.kitchen`.
|
||||
* @property {string} domain Domain of the entity.
|
||||
* Example: `light`.
|
||||
* @property {string} object_id Object ID of entity.
|
||||
* Example: `kitchen`.
|
||||
* @property {string} name Name of the entity.
|
||||
* Based on `friendly_name` attribute with fall-back to object ID.
|
||||
* Example: `Kitchen Ceiling`.
|
||||
* @property {string} last_updated Time the state was written to the state machine in UTC time.
|
||||
* Note that writing the exact same state including attributes will not result in this
|
||||
* field being updated.
|
||||
* Example: `2017-10-28 08:13:36.715874+00:00`.
|
||||
* @property {string} last_changed Time the state changed in the state machine in UTC time.
|
||||
* This is not updated when there are only updated attributes.
|
||||
* Example: `2017-10-28 08:13:36.715874+00:00`.
|
||||
* @property {stateAttributes} attributes A dictionary with extra attributes related to the current state.
|
||||
* @property {stateContext} context A dictionary with extra attributes related to the context of the state.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://www.home-assistant.io/docs/configuration/state_object/
|
||||
*/
|
||||
|
||||
/**
|
||||
* The attributes of an entity are optional.
|
||||
*
|
||||
* There are a few attributes that are used by Home Assistant for representing the entity in a specific way.
|
||||
* Each integration will also have its own attributes to represent extra state data about the entity.
|
||||
* For example, the light integration has attributes for the current brightness and color of the light.
|
||||
*
|
||||
* When an attribute is not available, Home Assistant will not write it to the state.
|
||||
*
|
||||
* @typedef {Object} stateAttributes State attributes.
|
||||
* @property {string} friendly_name Name of the entity.
|
||||
* Example: `Kitchen Ceiling`.
|
||||
* @property {string} icon Icon to use for the entity in the frontend.
|
||||
* Example: `mdi:home`.
|
||||
* @property {string} entity_picture URL to a picture that should be used instead of showing the domain icon.
|
||||
* @property {string} assumed_state Boolean if the current state is an assumption.
|
||||
* @property {string} unit_of_measurement The unit of measurement the state is expressed in.
|
||||
* Used for grouping graphs or understanding the entity.
|
||||
* Example: `°C`.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://www.home-assistant.io/docs/configuration/state_object/#attributes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context is used to tie events and states together in Home Assistant. Whenever an automation or user interaction
|
||||
* causes states to change, a new context is assigned. This context will be attached to all events and states that
|
||||
* happen as a result of the change.
|
||||
*
|
||||
* @typedef {Object} stateContext State context.
|
||||
* @property {string} context_id Unique identifier for the context.
|
||||
* @property {string} user_id Unique identifier of the user that started the change.
|
||||
* Will be None if action was not started by a user (i.e., started by an automation)
|
||||
* @property {string} parent_id Unique identifier of the parent context that started the change, if available.
|
||||
* For example, if an automation is triggered, the context of the trigger will be set as
|
||||
* parent.
|
||||
* @see https://www.home-assistant.io/docs/configuration/state_object/#context
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} areaFilterContext fer Card options.
|
||||
* @property {areaEntity} area Area Entity.
|
||||
* @property {string} domain Domain of the entity.
|
||||
* Example: `light`.
|
||||
* @property {string[]} areaDeviceIds The id of devices which are linked to the area entity.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
export {};
|
22
src/types/homeassistant/README.md
Normal file
22
src/types/homeassistant/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
This directory contains partial code from
|
||||
the [Home Assistant Frontend repository](https://github.com/home-assistant/frontend).
|
||||
|
||||
The code mainly defines Home Assistant interfaces/types which are refactored to fit this repository.
|
||||
This means properties are added/removed from the originals and subtypes may have been changed.
|
||||
|
||||
The [Apache 2.0 License](https://github.com/home-assistant/frontend/blob/dev/LICENSE.md) applies to all files in this
|
||||
directory.
|
||||
|
||||
Copyright 2023 Ferry Cools
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
14
src/types/homeassistant/data/area_registry.ts
Normal file
14
src/types/homeassistant/data/area_registry.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Area Entity.
|
||||
*
|
||||
* @property {string} area_id The id of the area.
|
||||
* @property {string} name Name of the area.
|
||||
* @property {string|null} picture URL to a picture that should be used instead of showing the domain icon.
|
||||
* @property {string[]} aliases Array of aliases of the area.
|
||||
*/
|
||||
export interface AreaRegistryEntry {
|
||||
area_id: string;
|
||||
name: string;
|
||||
picture: string | null;
|
||||
aliases: string[];
|
||||
}
|
19
src/types/homeassistant/data/climate.ts
Normal file
19
src/types/homeassistant/data/climate.ts
Normal file
@ -0,0 +1,19 @@
|
||||
export const HVAC_MODES = [
|
||||
"auto",
|
||||
"heat_cool",
|
||||
"heat",
|
||||
"cool",
|
||||
"dry",
|
||||
"fan_only",
|
||||
"off",
|
||||
] as const;
|
||||
|
||||
export type HvacMode = (typeof HVAC_MODES)[number];
|
||||
|
||||
HVAC_MODES.reduce(
|
||||
(order, mode, index) => {
|
||||
order[mode] = index;
|
||||
return order;
|
||||
},
|
||||
{} as Record<HvacMode, number>
|
||||
);
|
38
src/types/homeassistant/data/device_registry.ts
Normal file
38
src/types/homeassistant/data/device_registry.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Device Entity.
|
||||
*
|
||||
* @property {string} id Unique ID of a device (generated by Home Assistant).
|
||||
* @property {string[]} config_entries
|
||||
* @property {Array} connections
|
||||
* @property {Array} identifiers
|
||||
* @property {string | null} manufacturer
|
||||
* @property {string | null} model
|
||||
* @property {string | null} name
|
||||
* @property {string | null} sw_version
|
||||
* @property {string | null} hw_version
|
||||
* @property {string | null} serial_number
|
||||
* @property {string | null} via_device_id
|
||||
* @property {string} area_id The Area which the device is placed in.
|
||||
* @property {string | null} name_by_user
|
||||
* @property {string[] | null} entry_type
|
||||
* @property {string | null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {string | null} configuration_url
|
||||
*/
|
||||
export interface DeviceRegistryEntry {
|
||||
id: string;
|
||||
config_entries: string[];
|
||||
connections: Array<[string, string]>;
|
||||
identifiers: Array<[string, string]>;
|
||||
manufacturer: string | null;
|
||||
model: string | null;
|
||||
name: string | null;
|
||||
sw_version: string | null;
|
||||
hw_version: string | null;
|
||||
serial_number: string | null;
|
||||
via_device_id: string | null;
|
||||
area_id: string | null;
|
||||
name_by_user: string | null;
|
||||
entry_type: "service" | null;
|
||||
disabled_by: "user" | "integration" | "config_entry" | null;
|
||||
configuration_url: string | null;
|
||||
}
|
97
src/types/homeassistant/data/entity_registry.ts
Normal file
97
src/types/homeassistant/data/entity_registry.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import {LightColor} from "./light";
|
||||
|
||||
type EntityCategory = "config" | "diagnostic";
|
||||
|
||||
export interface EntityRegistryDisplayEntry {
|
||||
entity_id: string;
|
||||
name?: string;
|
||||
device_id?: string;
|
||||
area_id?: string;
|
||||
hidden?: boolean;
|
||||
entity_category?: EntityCategory;
|
||||
translation_key?: string;
|
||||
platform?: string;
|
||||
display_precision?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Home assistant entity.
|
||||
*
|
||||
* @property {string} id
|
||||
* @property {string} entity_id The id of this entity.
|
||||
* @property {string} name The name of this entity.
|
||||
* @property {string | null} icon
|
||||
* @property {string | null} platform
|
||||
* @property {string | null} config_entry_id
|
||||
* @property {string | null} device_id The id of the device to which this entity is linked.
|
||||
* @property {string | null} area_id The id of the area to which this entity is linked.
|
||||
* @property {string | null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {Object} hidden_by Indicates by what this entity is hidden.
|
||||
* @property {EntityCategory | null} entity_category
|
||||
* @property {boolean} has_entity_name
|
||||
* @property {string} [original_name]
|
||||
* @property {string} unique_id
|
||||
* @property {string} [translation_key]
|
||||
* @property {EntityRegistryOptions | null} options
|
||||
*/
|
||||
export interface EntityRegistryEntry {
|
||||
id: string;
|
||||
entity_id: string;
|
||||
name: string | null;
|
||||
icon: string | null;
|
||||
platform: string;
|
||||
config_entry_id: string | null;
|
||||
device_id: string | null;
|
||||
area_id: string | null;
|
||||
disabled_by: "user" | "device" | "integration" | "config_entry" | null;
|
||||
hidden_by: Exclude<EntityRegistryEntry["disabled_by"], "config_entry">;
|
||||
entity_category: EntityCategory | null;
|
||||
has_entity_name: boolean;
|
||||
original_name?: string;
|
||||
unique_id: string;
|
||||
translation_key?: string;
|
||||
options: EntityRegistryOptions | null;
|
||||
}
|
||||
|
||||
export interface SensorEntityOptions {
|
||||
display_precision?: number | null;
|
||||
suggested_display_precision?: number | null;
|
||||
unit_of_measurement?: string | null;
|
||||
}
|
||||
|
||||
export interface LightEntityOptions {
|
||||
favorite_colors?: LightColor[];
|
||||
}
|
||||
|
||||
export interface NumberEntityOptions {
|
||||
unit_of_measurement?: string | null;
|
||||
}
|
||||
|
||||
export interface LockEntityOptions {
|
||||
default_code?: string | null;
|
||||
}
|
||||
|
||||
export interface WeatherEntityOptions {
|
||||
precipitation_unit?: string | null;
|
||||
pressure_unit?: string | null;
|
||||
temperature_unit?: string | null;
|
||||
visibility_unit?: string | null;
|
||||
wind_speed_unit?: string | null;
|
||||
}
|
||||
|
||||
export interface SwitchAsXEntityOptions {
|
||||
entity_id: string;
|
||||
}
|
||||
|
||||
export interface EntityRegistryOptions {
|
||||
number?: NumberEntityOptions;
|
||||
sensor?: SensorEntityOptions;
|
||||
lock?: LockEntityOptions;
|
||||
weather?: WeatherEntityOptions;
|
||||
light?: LightEntityOptions;
|
||||
switch_as_x?: SwitchAsXEntityOptions;
|
||||
conversation?: Record<string, unknown>;
|
||||
"cloud.alexa"?: Record<string, unknown>;
|
||||
"cloud.google_assistant"?: Record<string, unknown>;
|
||||
}
|
||||
|
6
src/types/homeassistant/data/light.ts
Normal file
6
src/types/homeassistant/data/light.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export type LightColor =
|
||||
| { color_temp_kelvin: number; }
|
||||
| { hs_color: [number, number]; }
|
||||
| { rgb_color: [number, number, number]; }
|
||||
| { rgbw_color: [number, number, number, number]; }
|
||||
| { rgbww_color: [number, number, number, number, number]; };
|
118
src/types/homeassistant/data/lovelace.ts
Normal file
118
src/types/homeassistant/data/lovelace.ts
Normal file
@ -0,0 +1,118 @@
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
|
||||
export type LovelaceStrategyConfig = {
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export interface LovelaceConfig {
|
||||
title?: string;
|
||||
strategy?: LovelaceStrategyConfig;
|
||||
views: LovelaceViewConfig[];
|
||||
background?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* View Config.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/views/
|
||||
*/
|
||||
export interface LovelaceViewConfig {
|
||||
index?: number;
|
||||
title?: string;
|
||||
type?: string;
|
||||
strategy?: LovelaceStrategyConfig;
|
||||
badges?: Array<string | LovelaceBadgeConfig>;
|
||||
cards?: LovelaceCardConfig[];
|
||||
path?: string;
|
||||
icon?: string;
|
||||
theme?: string;
|
||||
panel?: boolean;
|
||||
background?: string;
|
||||
visible?: boolean | ShowViewConfig[];
|
||||
subview?: boolean;
|
||||
back_path?: string;
|
||||
}
|
||||
|
||||
export interface ShowViewConfig {
|
||||
user?: string;
|
||||
}
|
||||
|
||||
export interface LovelaceBadgeConfig {
|
||||
type?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface LovelaceCardConfig {
|
||||
index?: number;
|
||||
view_index?: number;
|
||||
view_layout?: any;
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface ToggleActionConfig extends BaseActionConfig {
|
||||
action: "toggle";
|
||||
}
|
||||
|
||||
export interface CallServiceActionConfig extends BaseActionConfig {
|
||||
action: "call-service";
|
||||
service: string;
|
||||
target?: HassServiceTarget;
|
||||
// Property "service_data" is kept for backwards compatibility. Replaced by "data".
|
||||
service_data?: Record<string, unknown>;
|
||||
data?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface NavigateActionConfig extends BaseActionConfig {
|
||||
action: "navigate";
|
||||
navigation_path: string;
|
||||
navigation_replace?: boolean;
|
||||
}
|
||||
|
||||
export interface UrlActionConfig extends BaseActionConfig {
|
||||
action: "url";
|
||||
url_path: string;
|
||||
}
|
||||
|
||||
export interface MoreInfoActionConfig extends BaseActionConfig {
|
||||
action: "more-info";
|
||||
}
|
||||
|
||||
export interface AssistActionConfig extends BaseActionConfig {
|
||||
action: "assist";
|
||||
pipeline_id?: string;
|
||||
start_listening?: boolean;
|
||||
}
|
||||
|
||||
export interface NoActionConfig extends BaseActionConfig {
|
||||
action: "none";
|
||||
}
|
||||
|
||||
export interface CustomActionConfig extends BaseActionConfig {
|
||||
action: "fire-dom-event";
|
||||
}
|
||||
|
||||
export interface BaseActionConfig {
|
||||
action: string;
|
||||
confirmation?: ConfirmationRestrictionConfig;
|
||||
}
|
||||
|
||||
export interface ConfirmationRestrictionConfig {
|
||||
text?: string;
|
||||
exemptions?: RestrictionConfig[];
|
||||
}
|
||||
|
||||
export interface RestrictionConfig {
|
||||
user: string;
|
||||
}
|
||||
|
||||
export type ActionConfig =
|
||||
| ToggleActionConfig
|
||||
| CallServiceActionConfig
|
||||
| NavigateActionConfig
|
||||
| UrlActionConfig
|
||||
| MoreInfoActionConfig
|
||||
| AssistActionConfig
|
||||
| NoActionConfig
|
||||
| CustomActionConfig;
|
26
src/types/homeassistant/lovelace/cards/types.ts
Normal file
26
src/types/homeassistant/lovelace/cards/types.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import {LovelaceCardConfig} from "../../data/lovelace";
|
||||
|
||||
/**
|
||||
* Home Assistant Stack Card Config.
|
||||
*
|
||||
* @property {string} type The stack type.
|
||||
* @property {Object[]} cards The content of the stack.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/horizontal-stack/
|
||||
* @see https://www.home-assistant.io/dashboards/vertical-stack/
|
||||
*/
|
||||
export interface StackCardConfig extends LovelaceCardConfig {
|
||||
cards: LovelaceCardConfig[];
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Home Assistant Area Card Config.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/area/
|
||||
*/
|
||||
export interface AreaCardConfig extends LovelaceCardConfig {
|
||||
area: string;
|
||||
navigation_path?: string;
|
||||
show_camera?: boolean;
|
||||
}
|
41
src/types/homeassistant/panels/lovelave/cards/types.ts
Normal file
41
src/types/homeassistant/panels/lovelave/cards/types.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import {ActionConfig, LovelaceCardConfig} from "../../../data/lovelace";
|
||||
|
||||
/**
|
||||
* Home Assistant Picture Entity Config.
|
||||
*
|
||||
* @property {string} entity An entity_id used for the picture.
|
||||
* @property {string} [name] Overwrite entity name.
|
||||
* @property {string} [image] URL of an image.
|
||||
* @property {string} [camera_image] Camera entity_id to use. (not required if entity is already a camera-entity).
|
||||
* @property {string} [camera_view=auto] “live” will show the live view if stream is enabled.
|
||||
* @property {Record<string, unknown>} [state_image] Map entity states to images (state: image URL).
|
||||
* @property {string[]} [state_filter] State-based CSS filters.
|
||||
* @property {string} [aspect_ratio] Forces the height of the image to be a ratio of the width.
|
||||
* Valid formats: Height percentage value (23%) or ratio expressed with colon or “x”
|
||||
* separator (16:9 or 16x9).
|
||||
* For a ratio, the second element can be omitted and will default to “1”
|
||||
* (1.78 equals 1.78:1).
|
||||
* @property {ActionConfig} [tap_action] Action taken on card tap.
|
||||
* @property {ActionConfig} [hold_action] Action taken on card tap and hold.
|
||||
* @property {ActionConfig} [double_tap_action] Action taken on card double tap.
|
||||
* @property {boolean} [show_name=true] Shows name in footer.
|
||||
* @property {string} [theme=true] Override the used theme for this card with any loaded theme.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/picture-entity/
|
||||
*/
|
||||
export interface PictureEntityCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
camera_view?: "live" | "auto";
|
||||
state_image?: Record<string, unknown>;
|
||||
state_filter?: string[];
|
||||
aspect_ratio?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
show_name?: boolean;
|
||||
show_state?: boolean;
|
||||
theme?: string;
|
||||
}
|
95
src/types/homeassistant/types.ts
Normal file
95
src/types/homeassistant/types.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import {Auth, Connection, HassConfig, HassEntities, HassServices, MessageBase,} from "home-assistant-js-websocket";
|
||||
import {AreaRegistryEntry} from "./data/area_registry";
|
||||
import {DeviceRegistryEntry} from "./data/device_registry";
|
||||
import {EntityRegistryDisplayEntry} from "./data/entity_registry";
|
||||
|
||||
export interface Credential {
|
||||
auth_provider_type: string;
|
||||
auth_provider_id: string;
|
||||
}
|
||||
|
||||
export interface MFAModule {
|
||||
id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface CurrentUser {
|
||||
id: string;
|
||||
is_owner: boolean;
|
||||
is_admin: boolean;
|
||||
name: string;
|
||||
credentials: Credential[];
|
||||
mfa_modules: MFAModule[];
|
||||
}
|
||||
|
||||
export interface PanelInfo<T = Record<string, any> | null> {
|
||||
component_name: string;
|
||||
config: T;
|
||||
icon: string | null;
|
||||
title: string | null;
|
||||
url_path: string;
|
||||
config_panel_domain?: string;
|
||||
}
|
||||
|
||||
export interface Panels {
|
||||
[name: string]: PanelInfo;
|
||||
}
|
||||
|
||||
|
||||
export interface Translation {
|
||||
nativeName: string;
|
||||
isRTL: boolean;
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface TranslationMetadata {
|
||||
fragments: string[];
|
||||
translations: {
|
||||
[lang: string]: Translation;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Resources {
|
||||
[language: string]: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface HomeAssistant {
|
||||
auth: Auth & { external?: any };
|
||||
connection: Connection;
|
||||
connected: boolean;
|
||||
states: HassEntities;
|
||||
entities: { [id: string]: EntityRegistryDisplayEntry };
|
||||
devices: { [id: string]: DeviceRegistryEntry };
|
||||
areas: { [id: string]: AreaRegistryEntry };
|
||||
services: HassServices;
|
||||
config: HassConfig;
|
||||
themes: { [k: string]: any };
|
||||
selectedTheme: { [k: string]: any } | null;
|
||||
panels: Panels;
|
||||
panelUrl: string;
|
||||
// i18n
|
||||
// current effective language in that order:
|
||||
// - backend saved user selected language
|
||||
// - language in local app storage
|
||||
// - browser language
|
||||
// - english (en)
|
||||
language: string;
|
||||
// local stored language, keep that name for backward compatibility
|
||||
selectedLanguage: string | null;
|
||||
locale: { [k: string]: any };
|
||||
resources: Resources;
|
||||
localize: Function;
|
||||
translationMetadata: TranslationMetadata;
|
||||
suspendWhenHidden: boolean;
|
||||
enableShortcuts: boolean;
|
||||
vibrate: boolean;
|
||||
debugConnection: boolean;
|
||||
dockedSidebar: "docked" | "always_hidden" | "auto";
|
||||
defaultPanel: string;
|
||||
moreInfoEntityId: string | null;
|
||||
user?: CurrentUser;
|
||||
userData?: { [k: string]: any } | null;
|
||||
|
||||
callWS<T>(msg: MessageBase): Promise<T>;
|
||||
}
|
22
src/types/lovelace-mushroom/README.md
Normal file
22
src/types/lovelace-mushroom/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
This directory contains partial code from
|
||||
the [Lovelace Mushroom repository](https://github.com/piitaya/lovelace-mushroom).
|
||||
|
||||
The code mainly defines Home Assistant interfaces/types which are refactored to fit this repository.
|
||||
This means properties are added/removed from the originals and subtypes may have been changed.
|
||||
|
||||
The [Apache 2.0 License](https://github.com/home-assistant/frontend/blob/dev/LICENSE.md) applies to all files in this
|
||||
directory.
|
||||
|
||||
Copyright 2023 Ferry Cools
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
15
src/types/lovelace-mushroom/cards/chips-card.ts
Normal file
15
src/types/lovelace-mushroom/cards/chips-card.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {LovelaceChipConfig} from "../utils/lovelace/chip/types";
|
||||
|
||||
/**
|
||||
* Chips Card Configuration
|
||||
*
|
||||
* @param {LovelaceChipConfig[]} chips Chips Array
|
||||
* @param {string} [alignment=start] Chips alignment (end, center, justify), when empty default behavior is start.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/chips.md
|
||||
*/
|
||||
export interface ChipsCardConfig extends LovelaceCardConfig {
|
||||
chips: LovelaceChipConfig[];
|
||||
alignment?: string;
|
||||
}
|
23
src/types/lovelace-mushroom/cards/climate-card-config.ts
Normal file
23
src/types/lovelace-mushroom/cards/climate-card-config.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import {HvacMode} from "../../homeassistant/data/climate";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
|
||||
/**
|
||||
* Climate Card Config.
|
||||
*
|
||||
* @property {boolean} [show_temperature_control=false] Show buttons to control target temperature.
|
||||
* @property {HvacMode[]} [hvac_modes] List of hvac modes to display (auto, heat_cool, heat, cool, dry, fan_only, off).
|
||||
* @property {boolean} [collapsible_controls] Collapse controls when off.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/climate.md
|
||||
*/
|
||||
export type ClimateCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
show_temperature_control?: boolean;
|
||||
hvac_modes?: HvacMode[];
|
||||
collapsible_controls?: boolean;
|
||||
};
|
22
src/types/lovelace-mushroom/cards/cover-card-config.ts
Normal file
22
src/types/lovelace-mushroom/cards/cover-card-config.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Cover Card Config.
|
||||
*
|
||||
* @property {boolean} [show_buttons_control=false] Show buttons to open, close and stop cover.
|
||||
* @property {boolean} [show_position_control=false] Show a slider to control position of the cover.
|
||||
* @property {boolean} [show_tilt_position_control=false] Show a slider to control tilt position of the cover.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/cover.md
|
||||
*/
|
||||
export type CoverCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
show_buttons_control?: boolean;
|
||||
show_position_control?: boolean;
|
||||
show_tilt_position_control?: boolean;
|
||||
};
|
18
src/types/lovelace-mushroom/cards/entity-card-config.ts
Normal file
18
src/types/lovelace-mushroom/cards/entity-card-config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
|
||||
/**
|
||||
* Entity Card Config.
|
||||
*
|
||||
* @property {string} [icon_color=blue] Custom color for icon when entity is state is active.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/entity.md
|
||||
*/
|
||||
export type EntityCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_color?: string;
|
||||
};
|
24
src/types/lovelace-mushroom/cards/fan-card-config.ts
Normal file
24
src/types/lovelace-mushroom/cards/fan-card-config.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Fan Card Config.
|
||||
*
|
||||
* @property {boolean} [icon_animation=false] Animate the icon when fan is on.
|
||||
* @property {boolean} [show_percentage_control=false] Show a slider to control speed.
|
||||
* @property {boolean} [show_oscillate_control=false] Show a button to control oscillation.
|
||||
* @property {boolean} [icon_animation=false] Animate the icon when fan is on.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/fan.md
|
||||
*/
|
||||
export type FanCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_animation?: boolean;
|
||||
show_percentage_control?: boolean;
|
||||
show_oscillate_control?: boolean;
|
||||
collapsible_controls?: boolean;
|
||||
};
|
29
src/types/lovelace-mushroom/cards/light-card-config.ts
Normal file
29
src/types/lovelace-mushroom/cards/light-card-config.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Light Card Config.
|
||||
*
|
||||
* @property {string} [icon_color=blue] Custom color for icon and brightness bar when the lights are on and
|
||||
* use_light_color is false.
|
||||
* @property {boolean} [show_brightness_control=false] Show a slider to control brightness.
|
||||
* @property {boolean} [show_color_temp_control=false] Show a slider to control temperature color.
|
||||
* @property {boolean} [show_color_control=false] Show a slider to control RGB color.
|
||||
* @property {boolean} [collapsible_controls=false] Collapse controls when off.
|
||||
* @property {boolean} [use_light_color=false] Colorize the icon and slider according light temperature or color.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/light.md
|
||||
*/
|
||||
export type LightCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_color?: string;
|
||||
show_brightness_control?: boolean;
|
||||
show_color_temp_control?: boolean;
|
||||
show_color_control?: boolean;
|
||||
collapsible_controls?: boolean;
|
||||
use_light_color?: boolean;
|
||||
};
|
14
src/types/lovelace-mushroom/cards/lock-card-config.ts
Normal file
14
src/types/lovelace-mushroom/cards/lock-card-config.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Lock Card Config.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/lock.md
|
||||
*/
|
||||
export type LockCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig;
|
@ -0,0 +1,45 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
export const MEDIA_LAYER_MEDIA_CONTROLS = [
|
||||
"on_off",
|
||||
"shuffle",
|
||||
"previous",
|
||||
"play_pause_stop",
|
||||
"next",
|
||||
"repeat",
|
||||
] as const;
|
||||
|
||||
export type MediaPlayerMediaControl = (typeof MEDIA_LAYER_MEDIA_CONTROLS)[number];
|
||||
|
||||
export const MEDIA_PLAYER_VOLUME_CONTROLS = [
|
||||
"volume_mute",
|
||||
"volume_set",
|
||||
"volume_buttons",
|
||||
] as const;
|
||||
|
||||
export type MediaPlayerVolumeControl = (typeof MEDIA_PLAYER_VOLUME_CONTROLS)[number];
|
||||
|
||||
/**
|
||||
* Media Player Card Config.
|
||||
*
|
||||
* @property {boolean} [use_media_info=false] Use media info instead of name, state, and icon when media is playing.
|
||||
* @property {boolean} [show_volume_level=false] Show volume level next to media state when media is playing.
|
||||
* @property {MediaPlayerVolumeControl[]} [volume_controls] List of controls to display (volume_mute, volume_set, volume_buttons)
|
||||
* @property {MediaPlayerMediaControl[]} [media_controls] List of controls to display (on_off, shuffle, previous, play_pause_stop, next, repeat)
|
||||
* @property {boolean} [collapsible_controls=false] Collapse controls when off
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/media-player.md
|
||||
*/
|
||||
export type MediaPlayerCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
use_media_info?: boolean;
|
||||
show_volume_level?: boolean;
|
||||
volume_controls?: MediaPlayerVolumeControl[];
|
||||
media_controls?: MediaPlayerMediaControl[];
|
||||
collapsible_controls?: boolean;
|
||||
};
|
24
src/types/lovelace-mushroom/cards/number-card-config.ts
Normal file
24
src/types/lovelace-mushroom/cards/number-card-config.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
export const DISPLAY_MODES = ["slider", "buttons"] as const;
|
||||
|
||||
type DisplayMode = (typeof DISPLAY_MODES)[number];
|
||||
|
||||
/**
|
||||
* Number Card Config.
|
||||
*
|
||||
* @property {string} [icon_color=blue] Custom color for icon when entity state is active.
|
||||
* @property {DisplayMode} [display_mode=slider] Slider or Button controls.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/number.md
|
||||
*/
|
||||
export type NumberCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_color?: string;
|
||||
display_mode?: DisplayMode;
|
||||
};
|
14
src/types/lovelace-mushroom/cards/person-card-config.ts
Normal file
14
src/types/lovelace-mushroom/cards/person-card-config.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Person Card Config.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/person.md
|
||||
*/
|
||||
export type PersonCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig;
|
36
src/types/lovelace-mushroom/cards/template-card-config.ts
Normal file
36
src/types/lovelace-mushroom/cards/template-card-config.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Template Card Config.
|
||||
*
|
||||
* @property {string} [entity]
|
||||
* @property {string} [icon] Icon to render. May contain templates.
|
||||
* @property {string} [icon_color] Icon color to render. May contain templates.
|
||||
* @property {string} [primary] Primary info to render. May contain templates.
|
||||
* @property {string} [secondary] Secondary info to render. May contain templates.
|
||||
* @property {string} [badge_icon] Badge icon to render. May contain templates.
|
||||
* @property {string} [badge_color] Badge icon color to render. May contain templates.
|
||||
* @property {string} [picture] Picture to render. May contain templates.
|
||||
* @property {boolean} [multiline_secondary] Enables support for multiline text for the secondary info.
|
||||
* @property {string | string[]} [entity_id] Only reacts to the state changes of these entities.
|
||||
* This can be used if the automatic analysis fails to find all relevant
|
||||
* entities.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/template.md
|
||||
*/
|
||||
export type TemplateCardConfig = LovelaceCardConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
entity?: string;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
primary?: string;
|
||||
secondary?: string;
|
||||
badge_icon?: string;
|
||||
badge_color?: string;
|
||||
picture?: string;
|
||||
multiline_secondary?: boolean;
|
||||
entity_id?: string | string[];
|
||||
};
|
21
src/types/lovelace-mushroom/cards/title-card-config.ts
Normal file
21
src/types/lovelace-mushroom/cards/title-card-config.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import {ActionConfig, LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
|
||||
/**
|
||||
* Title Card Config.
|
||||
*
|
||||
* @property {string} [title] Title to render. May contain templates.
|
||||
* @property {string} [subtitle] Subtitle to render. May contain templates.
|
||||
* @property {ActionConfig} [title_tap_action=none] Home assistant action to perform on title tap.
|
||||
* @property {ActionConfig} [subtitle_tap_action=none] Home assistant action to perform on subtitle tap.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/title.md
|
||||
*/
|
||||
export interface TitleCardConfig extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
alignment?: string;
|
||||
title_tap_action?: ActionConfig;
|
||||
subtitle_tap_action?: ActionConfig;
|
||||
}
|
||||
|
||||
|
31
src/types/lovelace-mushroom/cards/vacuum-card-config.ts
Normal file
31
src/types/lovelace-mushroom/cards/vacuum-card-config.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
export const VACUUM_COMMANDS = [
|
||||
"on_off",
|
||||
"start_pause",
|
||||
"stop",
|
||||
"locate",
|
||||
"clean_spot",
|
||||
"return_home",
|
||||
] as const;
|
||||
|
||||
export type VacuumCommand = (typeof VACUUM_COMMANDS)[number];
|
||||
|
||||
/**
|
||||
* Vacuum Card Config.
|
||||
*
|
||||
* @param {boolean} icon_animation Animate the icon when vacuum is cleaning.
|
||||
* @param {VacuumCommand[]} commands List of commands to display (start_pause, stop, locate, clean_spot, return_home).
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/vacuum.md
|
||||
*/
|
||||
export type VacuumCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_animation?: boolean;
|
||||
commands?: VacuumCommand[];
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
import {ActionConfig} from "../../../homeassistant/data/lovelace";
|
||||
|
||||
export type ActionsSharedConfig = {
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
@ -0,0 +1,13 @@
|
||||
import {boolean, enums, Infer, object, optional} from "superstruct";
|
||||
import {layoutStruct} from "./utils/layout";
|
||||
import {ICON_TYPES, INFOS} from "./utils/info";
|
||||
|
||||
export const appearanceSharedConfigStruct = object({
|
||||
layout: optional(layoutStruct),
|
||||
fill_container: optional(boolean()),
|
||||
primary_info: optional(enums(INFOS)),
|
||||
secondary_info: optional(enums(INFOS)),
|
||||
icon_type: optional(enums(ICON_TYPES)),
|
||||
});
|
||||
|
||||
export type AppearanceSharedConfig = Infer<typeof appearanceSharedConfigStruct>;
|
@ -0,0 +1,9 @@
|
||||
import {Infer, object, optional, string} from "superstruct";
|
||||
|
||||
export const entitySharedConfigStruct = object({
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
icon: optional(string()),
|
||||
});
|
||||
|
||||
export type EntitySharedConfig = Infer<typeof entitySharedConfigStruct>;
|
2
src/types/lovelace-mushroom/shared/config/utils/info.ts
Normal file
2
src/types/lovelace-mushroom/shared/config/utils/info.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const INFOS = ["name", "state", "last-changed", "last-updated", "none"] as const;
|
||||
export const ICON_TYPES = ["icon", "entity-picture", "none"] as const;
|
@ -0,0 +1,3 @@
|
||||
import {literal, union} from "superstruct";
|
||||
|
||||
export const layoutStruct = union([literal("horizontal"), literal("vertical"), literal("default")]);
|
2
src/types/lovelace-mushroom/utils/info.ts
Normal file
2
src/types/lovelace-mushroom/utils/info.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const INFOS = ["name", "state", "last-changed", "last-updated", "none"] as const;
|
||||
export type Info = (typeof INFOS)[number];
|
202
src/types/lovelace-mushroom/utils/lovelace/chip/types.ts
Normal file
202
src/types/lovelace-mushroom/utils/lovelace/chip/types.ts
Normal file
@ -0,0 +1,202 @@
|
||||
import {ActionConfig} from "../../../../homeassistant/data/lovelace";
|
||||
import {Info} from "../../info";
|
||||
|
||||
/**
|
||||
* Action Chip Config
|
||||
*
|
||||
* @property {"action"} type Type of the chip.
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type ActionChipConfig = {
|
||||
type: "action";
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Alarm Control Panel Chip Config
|
||||
*
|
||||
* @property {"alarm-control-panel"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {string} [name] Custom name.
|
||||
* @property {string} [content_info] Custom content.
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type AlarmControlPanelChipConfig = {
|
||||
type: "alarm-control-panel";
|
||||
entity?: string;
|
||||
name?: string;
|
||||
content_info?: Info;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Back Chip Config
|
||||
*
|
||||
* @property {"back"} type Type of the chip.
|
||||
* @property {string} [icon] Custom icon.
|
||||
*/
|
||||
export type BackChipConfig = {
|
||||
type: "back";
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entity Chip Config
|
||||
*
|
||||
* @property {"entity"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {string} [name] Custom name.
|
||||
* @property {string} [content_info] Custom content.
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {boolean} [use_entity_picture]
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type EntityChipConfig = {
|
||||
type: "entity";
|
||||
entity?: string;
|
||||
name?: string;
|
||||
content_info?: Info;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
use_entity_picture?: boolean;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Menu Chip Config
|
||||
*
|
||||
* @property {"menu"} type Type of the chip.
|
||||
* @property {string} [icon] Custom icon.
|
||||
*/
|
||||
export type MenuChipConfig = {
|
||||
type: "menu";
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Weather Chip Config
|
||||
*
|
||||
* @property {"weather"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
* @property {boolean} [show_temperature] Show the temperature.
|
||||
* @property {boolean} [show_conditions] Show the conditions.
|
||||
*/
|
||||
export type WeatherChipConfig = {
|
||||
type: "weather";
|
||||
entity?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
show_temperature?: boolean;
|
||||
show_conditions?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Template Chip Config
|
||||
*
|
||||
* @property {"template"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
* @property {string} [content]
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {string} [picture]
|
||||
* @property {string | string[]} [entity_id]
|
||||
*/
|
||||
export type TemplateChipConfig = {
|
||||
type: "template";
|
||||
entity?: string;
|
||||
hold_action?: ActionConfig;
|
||||
tap_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
content?: string;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
picture?: string;
|
||||
entity_id?: string | string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Conditional Chip Config
|
||||
*
|
||||
* @property {"conditional"} type Type of the chip.
|
||||
* @property {LovelaceChipConfig} [chip] A chip configuration.
|
||||
* @property {[]} conditions
|
||||
*/
|
||||
export interface ConditionalChipConfig {
|
||||
type: "conditional";
|
||||
chip?: LovelaceChipConfig;
|
||||
conditions: any[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Light Chip Config
|
||||
*
|
||||
* @property {"light"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {string} [name]
|
||||
* @property {Info} [content_info]
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {boolean} [use_light_color] Colorize the icon and slider according light temperature or color.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type LightChipConfig = {
|
||||
type: "light";
|
||||
entity?: string;
|
||||
name?: string;
|
||||
content_info?: Info;
|
||||
icon?: string;
|
||||
use_light_color?: boolean;
|
||||
hold_action?: ActionConfig;
|
||||
tap_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Spacer Chip Config
|
||||
*
|
||||
* @property {"spacer"} type Type of the chip.
|
||||
*/
|
||||
export type SpacerChipConfig = {
|
||||
type: "spacer";
|
||||
};
|
||||
|
||||
export type LovelaceChipConfig =
|
||||
| ActionChipConfig
|
||||
| AlarmControlPanelChipConfig
|
||||
| BackChipConfig
|
||||
| EntityChipConfig
|
||||
| MenuChipConfig
|
||||
| WeatherChipConfig
|
||||
| TemplateChipConfig
|
||||
| ConditionalChipConfig
|
||||
| LightChipConfig
|
||||
| SpacerChipConfig;
|
70
src/types/strategy/cards.ts
Normal file
70
src/types/strategy/cards.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import {LovelaceCardConfig} from "../homeassistant/data/lovelace";
|
||||
import {TitleCardConfig} from "../lovelace-mushroom/cards/title-card-config";
|
||||
import {EntitySharedConfig} from "../lovelace-mushroom/shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../lovelace-mushroom/shared/config/appearance-config";
|
||||
import {ActionsSharedConfig} from "../lovelace-mushroom/shared/config/actions-config";
|
||||
import {TemplateCardConfig} from "../lovelace-mushroom/cards/template-card-config";
|
||||
import {EntityCardConfig} from "../lovelace-mushroom/cards/entity-card-config";
|
||||
import {PictureEntityCardConfig} from "../homeassistant/panels/lovelave/cards/types";
|
||||
import {ClimateCardConfig} from "../lovelace-mushroom/cards/climate-card-config";
|
||||
import {CoverCardConfig} from "../lovelace-mushroom/cards/cover-card-config";
|
||||
import {FanCardConfig} from "../lovelace-mushroom/cards/fan-card-config";
|
||||
import {AreaCardConfig} from "../homeassistant/lovelace/cards/types";
|
||||
import {LightCardConfig} from "../lovelace-mushroom/cards/light-card-config";
|
||||
import {LockCardConfig} from "../lovelace-mushroom/cards/lock-card-config";
|
||||
import {MediaPlayerCardConfig} from "../lovelace-mushroom/cards/media-player-card-config";
|
||||
import {NumberCardConfig} from "../lovelace-mushroom/cards/number-card-config";
|
||||
import {PersonCardConfig} from "../lovelace-mushroom/cards/person-card-config";
|
||||
import {VacuumCardConfig} from "../lovelace-mushroom/cards/vacuum-card-config";
|
||||
|
||||
export namespace cards {
|
||||
/**
|
||||
* Abstract Card Config.
|
||||
*/
|
||||
export type AbstractCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig;
|
||||
|
||||
/**
|
||||
* Controller Card Config.
|
||||
*
|
||||
* @property {boolean} [showControls=true] False to hide controls.
|
||||
* @property {string} [iconOn] Icon to show for switching entities from off state.
|
||||
* @property {string} [iconOff] Icon to show for switching entities to off state.
|
||||
* @property {string} [onService=none] Service to call for switching entities from off state.
|
||||
* @property {string} [offService=none] Service to call for switching entities to off state.
|
||||
*/
|
||||
export interface ControllerCardConfig extends TitleCardConfig {
|
||||
type: "mushroom-title-card",
|
||||
showControls?: boolean;
|
||||
iconOn?: string;
|
||||
iconOff?: string;
|
||||
onService?: string;
|
||||
offService?: string;
|
||||
}
|
||||
|
||||
export type AreaCardOptions = Omit<AreaCardConfig, "type">;
|
||||
export type ClimateCardOptions = Omit<ClimateCardConfig, "type">;
|
||||
export type ControllerCardOptions = Omit<ControllerCardConfig, "type">;
|
||||
export type CoverCardOptions = Omit<CoverCardConfig, "type">;
|
||||
export type EntityCardOptions = Omit<EntityCardConfig, "type">;
|
||||
export type FanCardOptions = Omit<FanCardConfig, "type">;
|
||||
export type LightCardOptions = Omit<LightCardConfig, "type">;
|
||||
export type LockCardOptions = Omit<LockCardConfig, "type">;
|
||||
export type MediaPlayerCardOptions = Omit<MediaPlayerCardConfig, "type">;
|
||||
export type NumberCardOptions = Omit<NumberCardConfig, "type">;
|
||||
export type PersonCardOptions = Omit<PersonCardConfig, "type">;
|
||||
export type PictureEntityCardOptions = Omit<PictureEntityCardConfig, "type">;
|
||||
export type TemplateCardOptions = Omit<TemplateCardConfig, "type">;
|
||||
export type VacuumCardOptions = Omit<VacuumCardConfig, "type">;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
6
src/types/strategy/chips.ts
Normal file
6
src/types/strategy/chips.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {TemplateChipConfig, WeatherChipConfig} from "../lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
export namespace chips {
|
||||
export type TemplateChipOptions = Omit<TemplateChipConfig, "type">;
|
||||
export type WeatherChipOptions = Omit<WeatherChipConfig, "type">;
|
||||
}
|
214
src/types/strategy/generic.ts
Normal file
214
src/types/strategy/generic.ts
Normal file
@ -0,0 +1,214 @@
|
||||
import {
|
||||
CallServiceActionConfig,
|
||||
LovelaceCardConfig,
|
||||
LovelaceConfig,
|
||||
LovelaceViewConfig
|
||||
} from "../homeassistant/data/lovelace";
|
||||
import {HomeAssistant} from "../homeassistant/types";
|
||||
import {AreaRegistryEntry} from "../homeassistant/data/area_registry";
|
||||
import {cards} from "./cards";
|
||||
import {EntityRegistryEntry} from "../homeassistant/data/entity_registry";
|
||||
import {LovelaceChipConfig} from "../lovelace-mushroom/utils/lovelace/chip/types";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
|
||||
export namespace generic {
|
||||
/**
|
||||
* An entry out of a Home Assistant Register.
|
||||
*/
|
||||
export type RegistryEntry =
|
||||
| AreaRegistryEntry
|
||||
| DataTransfer
|
||||
| EntityRegistryEntry
|
||||
|
||||
/**
|
||||
* View Entity.
|
||||
*
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
*/
|
||||
export interface ViewConfig extends LovelaceViewConfig {
|
||||
hidden?: boolean;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain Configuration.
|
||||
*
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
*/
|
||||
export interface DomainConfig extends Partial<cards.ControllerCardConfig> {
|
||||
hidden?: boolean;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Information Object.
|
||||
*
|
||||
* Home Assistant passes this object to the Dashboard Generator method.
|
||||
*
|
||||
* @property {LovelaceConfig} config Dashboard configuration.
|
||||
* @property {HomeAssistant} hass The Home Assistant object.
|
||||
*
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#dashboard-strategies
|
||||
*/
|
||||
export interface DashBoardInfo {
|
||||
config?: LovelaceConfig & {
|
||||
strategy: {
|
||||
options?: StrategyConfig
|
||||
}
|
||||
};
|
||||
hass: HomeAssistant;
|
||||
}
|
||||
|
||||
/**
|
||||
* View Information Object.
|
||||
*
|
||||
* Home Assistant passes this object to the View Generator method.
|
||||
*
|
||||
* @property {LovelaceViewConfig} view View configuration.
|
||||
* @property {LovelaceConfig} config Dashboard configuration.
|
||||
* @property {HomeAssistant} hass The Home Assistant object.
|
||||
*
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#view-strategies
|
||||
*/
|
||||
export interface ViewInfo {
|
||||
view: LovelaceViewConfig & {
|
||||
strategy?: {
|
||||
options?: StrategyConfig & { area: StrategyArea }
|
||||
}
|
||||
};
|
||||
config: LovelaceConfig
|
||||
hass: HomeAssistant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy Configuration.
|
||||
*
|
||||
* @property {Object.<AreaRegistryEntry>} areas List of areas.
|
||||
* @property {Object.<CustomCardConfig>} [card_options] Card options for entities.
|
||||
* @property {chips} [chips] List of chips to show in the Home view.
|
||||
* @property {boolean} [debug] Set to true for more verbose debugging info.
|
||||
* @property {Object.<DomainConfig>} domains List of domains.
|
||||
* @property {object[]} [extra_cards] List of cards to show below room cards.
|
||||
* @property {object[]} [extra_views] List of views to add to the dashboard.
|
||||
* @property {object[]} [quick_access_cards] List of cards to show between welcome card and rooms cards.
|
||||
* @property {Object.<ViewConfig>} views List of views.
|
||||
*/
|
||||
export interface StrategyConfig {
|
||||
areas: { [k: string]: StrategyArea };
|
||||
card_options?: { [k: string]: CustomCardConfig };
|
||||
chips?: Chips;
|
||||
debug: boolean;
|
||||
domains: { [k: string]: DomainConfig };
|
||||
extra_cards?: LovelaceCardConfig[];
|
||||
extra_views?: ViewConfig[];
|
||||
home_view: {
|
||||
hidden: HiddenSectionType[]
|
||||
}
|
||||
quick_access_cards?: LovelaceCardConfig[];
|
||||
views: { [k: string]: ViewConfig };
|
||||
}
|
||||
|
||||
const hiddenSectionList = ["chips", "persons", "greeting", "areas", "areasTitle"] as const;
|
||||
export type HiddenSectionType = typeof hiddenSectionList[number];
|
||||
|
||||
/**
|
||||
* Represents the default configuration for a strategy.
|
||||
*/
|
||||
export interface StrategyDefaults extends StrategyConfig {
|
||||
areas: {
|
||||
undisclosed: StrategyArea & {
|
||||
area_id: "undisclosed",
|
||||
},
|
||||
[k: string]: StrategyArea,
|
||||
},
|
||||
domains: {
|
||||
default: DomainConfig,
|
||||
[k: string]: DomainConfig,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy Area.
|
||||
*
|
||||
* @property {number} [order] Ordering position of the area in the list of available areas.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* @property {object[]} [extra_cards] An array of card configurations.
|
||||
* The configured cards are added to the dashboard.
|
||||
* @property {string} [type=default] The type of area card.
|
||||
*/
|
||||
export interface StrategyArea extends AreaRegistryEntry {
|
||||
order?: number;
|
||||
hidden?: boolean;
|
||||
extra_cards?: LovelaceCardConfig[];
|
||||
type?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of chips to show in the Home view.
|
||||
*
|
||||
* @property {boolean} light_count Chip to display the number of lights on.
|
||||
* @property {boolean} fan_count Chip to display the number of fans on.
|
||||
* @property {boolean} cover_count Chip to display the number of unclosed covers.
|
||||
* @property {boolean} switch_count Chip to display the number of switches on.
|
||||
* @property {boolean} climate_count Chip to display the number of climates which are not off.
|
||||
* @property {string} weather_entity Entity ID for the weather chip to use, accepts `weather.` only.
|
||||
* @property {object[]} extra_chips List of extra chips.
|
||||
*/
|
||||
export interface Chips {
|
||||
extra_chips: LovelaceChipConfig[];
|
||||
|
||||
light_count: boolean;
|
||||
fan_count: boolean;
|
||||
cover_count: boolean;
|
||||
switch_count: boolean;
|
||||
climate_count: boolean;
|
||||
weather_entity: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Card Configuration for an entity.
|
||||
*
|
||||
* @property {boolean} hidden True if the entity should be hidden from the dashboard.
|
||||
*/
|
||||
export interface CustomCardConfig extends LovelaceCardConfig {
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Area Filter Context.
|
||||
*
|
||||
* @property {AreaRegistryEntry} area Area Entity.
|
||||
* @property {string[]} areaDeviceIds The id of devices which are linked to the area entity.
|
||||
* @property {string} domain Domain of the entity.
|
||||
* Example: `light`.
|
||||
*/
|
||||
export interface AreaFilterContext {
|
||||
area: AreaRegistryEntry;
|
||||
areaDeviceIds: string[];
|
||||
domain: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given object is an instance of CallServiceActionConfig.
|
||||
*
|
||||
* @param {any} obj - The object to be checked.
|
||||
* @return {boolean} - Returns true if the object is an instance of CallServiceActionConfig, otherwise false.
|
||||
*/
|
||||
export function isCallServiceActionConfig(obj: any): obj is CallServiceActionConfig {
|
||||
return obj && obj.action === "call-service" && ["action", "service"].every(key => key in obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given object is an instance of HassServiceTarget.
|
||||
*
|
||||
* @param {any} obj - The object to check.
|
||||
* @return {boolean} - True if the object is an instance of HassServiceTarget, false otherwise.
|
||||
*/
|
||||
export function isCallServiceActionTarget(obj: any): obj is HassServiceTarget {
|
||||
return obj && ["entity_id", "device_id", "area_id"].some(key => key in obj);
|
||||
}
|
||||
}
|
17
src/types/strategy/views.ts
Normal file
17
src/types/strategy/views.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import {cards} from "./cards";
|
||||
import {LovelaceViewConfig} from "../homeassistant/data/lovelace";
|
||||
|
||||
export namespace views {
|
||||
/**
|
||||
* Options for the extended View class.
|
||||
*
|
||||
* @property {cards.ControllerCardConfig} [controllerCardOptions] Options for the Controller card.
|
||||
*/
|
||||
export interface ViewConfig extends LovelaceViewConfig {
|
||||
controllerCardOptions?: cards.ControllerCardOptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,131 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {TitleCard} from "../cards/TitleCard";
|
||||
|
||||
/**
|
||||
* Abstract View Class.
|
||||
*
|
||||
* To create a new view, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
class AbstractView {
|
||||
/**
|
||||
* Options for creating a view.
|
||||
*
|
||||
* @type {abstractOptions}
|
||||
*/
|
||||
options = {
|
||||
title: null,
|
||||
path: null,
|
||||
icon: "mdi:view-dashboard",
|
||||
subview: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* A card to switch all entities in the view.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
viewTitleCard;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @throws {Error} If trying to instantiate this class.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor() {
|
||||
if (this.constructor === AbstractView) {
|
||||
throw new Error("Abstract classes can't be instantiated.");
|
||||
}
|
||||
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the default options of this class and the custom options into the options of the parent class.
|
||||
*
|
||||
* @param {Object} [defaultOptions={}] Default options for the card.
|
||||
* @param {Object} [customOptions={}] Custom Options for the card.
|
||||
*/
|
||||
mergeOptions(defaultOptions, customOptions) {
|
||||
this.options = {
|
||||
...defaultOptions,
|
||||
...customOptions,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the cards to include in the view.
|
||||
*
|
||||
* @return {Object[] | Promise} An array of card objects.
|
||||
*/
|
||||
async createViewCards() {
|
||||
/** @type Object[] */
|
||||
const viewCards = [];
|
||||
|
||||
// Create cards for each area.
|
||||
for (const area of Helper.areas) {
|
||||
const areaCards = [];
|
||||
const entities = Helper.getDeviceEntities(area, this["domain"]);
|
||||
const className = Helper.sanitizeClassName(this["domain"] + "Card");
|
||||
const cardModule = await import(`../cards/${className}`);
|
||||
|
||||
// Create a card for each domain-entity of the current area.
|
||||
for (const entity of entities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id] ?? {};
|
||||
|
||||
if (cardOptions.hidden || deviceOptions.hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
areaCards.push(new cardModule[className](entity, cardOptions).getCard());
|
||||
}
|
||||
|
||||
if (areaCards.length) {
|
||||
// Create a Title card for the current area if it has entities.
|
||||
areaCards.unshift(new TitleCard(
|
||||
[area],
|
||||
{
|
||||
title: area.name,
|
||||
...this.options["titleCard"],
|
||||
},
|
||||
this["domain"],
|
||||
).createCard());
|
||||
|
||||
viewCards.push({
|
||||
type: "vertical-stack",
|
||||
cards: areaCards,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
viewCards.unshift(viewCards.length ? this.viewTitleCard : {
|
||||
type: "custom:mushroom-title-card",
|
||||
title: "No Entities Available",
|
||||
subtitle: "They're either hidden by the configuration or by Home Assistant.",
|
||||
});
|
||||
|
||||
return viewCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a view object.
|
||||
*
|
||||
* The view includes the cards which are created by method createViewCards().
|
||||
*
|
||||
* @returns {viewOptions & {cards: Object[]}} The view object.
|
||||
*/
|
||||
async getView() {
|
||||
return {
|
||||
...this.options,
|
||||
cards: await this.createViewCards(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractView};
|
158
src/views/AbstractView.ts
Normal file
158
src/views/AbstractView.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {ControllerCard} from "../cards/ControllerCard";
|
||||
import {StackCardConfig} from "../types/homeassistant/lovelace/cards/types";
|
||||
import {LovelaceCardConfig, LovelaceViewConfig} from "../types/homeassistant/data/lovelace";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {TitleCardConfig} from "../types/lovelace-mushroom/cards/title-card-config";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
import abstractCardConfig = cards.AbstractCardConfig;
|
||||
|
||||
/**
|
||||
* Abstract View Class.
|
||||
*
|
||||
* To create a new view, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
abstract class AbstractView {
|
||||
/**
|
||||
* Configuration of the view.
|
||||
*
|
||||
* @type {LovelaceViewConfig}
|
||||
*/
|
||||
config: LovelaceViewConfig = {
|
||||
icon: "mdi:view-dashboard",
|
||||
subview: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* A card to switch all entities in the view.
|
||||
*
|
||||
* @type {StackCardConfig}
|
||||
*/
|
||||
viewControllerCard: StackCardConfig = {
|
||||
cards: [],
|
||||
type: "",
|
||||
};
|
||||
|
||||
/**
|
||||
* The domain of which we operate the devices.
|
||||
*
|
||||
* @private
|
||||
* @readonly
|
||||
*/
|
||||
readonly #domain?: string;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {string} [domain] The domain which the view is representing.
|
||||
*
|
||||
* @throws {Error} If trying to instantiate this class.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
protected constructor(domain: string = "") {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
this.#domain = domain;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the cards to include in the view.
|
||||
*
|
||||
* @return {Promise<(StackCardConfig | TitleCardConfig)[]>} An array of card objects.
|
||||
*/
|
||||
async createViewCards(): Promise<(StackCardConfig | TitleCardConfig)[]> {
|
||||
const viewCards: LovelaceCardConfig[] = [];
|
||||
|
||||
// Create cards for each area.
|
||||
for (const area of Helper.areas) {
|
||||
const areaCards: abstractCardConfig[] = [];
|
||||
const entities = Helper.getDeviceEntities(area, this.#domain ?? "");
|
||||
const className = Helper.sanitizeClassName(this.#domain + "Card");
|
||||
const cardModule = await import(`../cards/${className}`);
|
||||
|
||||
// Set the target for controller cards to the current area.
|
||||
let target: HassServiceTarget = {
|
||||
area_id: [area.area_id],
|
||||
};
|
||||
|
||||
// Set the target for controller cards to entities without an area.
|
||||
if (area.area_id === "undisclosed") {
|
||||
target = {
|
||||
entity_id: entities.map(entity => entity.entity_id),
|
||||
}
|
||||
}
|
||||
|
||||
// Create a card for each domain-entity of the current area.
|
||||
for (const entity of entities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id ?? "null"];
|
||||
|
||||
if (cardOptions?.hidden || deviceOptions?.hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
areaCards.push(new cardModule[className](entity, cardOptions).getCard());
|
||||
}
|
||||
|
||||
// Vertical stack the area cards if it has entities.
|
||||
if (areaCards.length) {
|
||||
const titleCardOptions = ("controllerCardOptions" in this.config) ? this.config.controllerCardOptions : {};
|
||||
|
||||
// Create and insert a Controller card.
|
||||
areaCards.unshift(new ControllerCard(target, Object.assign({title: area.name}, titleCardOptions)).createCard());
|
||||
|
||||
viewCards.push({
|
||||
type: "vertical-stack",
|
||||
cards: areaCards,
|
||||
} as StackCardConfig);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a Controller Card for all the entities in the view.
|
||||
if (viewCards.length) {
|
||||
viewCards.unshift(this.viewControllerCard);
|
||||
}
|
||||
|
||||
return viewCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a view object.
|
||||
*
|
||||
* The view includes the cards which are created by method createViewCards().
|
||||
*
|
||||
* @returns {Promise<LovelaceViewConfig>} The view object.
|
||||
*/
|
||||
async getView(): Promise<LovelaceViewConfig> {
|
||||
return {
|
||||
...this.config,
|
||||
cards: await this.createViewCards(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a target of entity IDs for the given domain.
|
||||
*
|
||||
* @param {string} domain - The target domain to retrieve entity IDs from.
|
||||
* @return {HassServiceTarget} - A target for a service call.
|
||||
*/
|
||||
targetDomain(domain: string): HassServiceTarget {
|
||||
return {
|
||||
entity_id: Helper.entities.filter(
|
||||
entity =>
|
||||
entity.entity_id.startsWith(domain + ".")
|
||||
&& !entity.hidden_by
|
||||
&& !Helper.strategyOptions.card_options?.entity_id.hidden
|
||||
).map(entity => entity.entity_id),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractView};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user