Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tronikos committed Jul 18, 2023
0 parents commit 22b27cb
Show file tree
Hide file tree
Showing 11 changed files with 336 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/hassfest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Validate with hassfest

on:
push:
pull_request:
schedule:
- cron: '0 0 * * *'

jobs:
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v3"
- uses: "home-assistant/actions/hassfest@master"
34 changes: 34 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: "Release"

on:
release:
types:
- published

jobs:
release:
name: "Release default_config_disabler"
runs-on: ubuntu-latest
steps:
- name: "⬇️ Checkout the repository"
uses: actions/checkout@v3

- name: "🔢 Adjust version number"
shell: bash
run: |
version="${{ github.event.release.tag_name }}"
version="${version,,}"
version="${version#v}"
yq e -P -o=json \
-i ".version = \"${version}\"" \
"${{ github.workspace }}/custom_components/default_config_disabler/manifest.json"
- name: "📦 Created zipped release package"
shell: bash
run: |
cd "${{ github.workspace }}/custom_components/default_config_disabler"
zip default_config_disabler.zip -r ./
- name: "⬆️ Upload zip to release"
uses: softprops/[email protected]
with:
files: ${{ github.workspace }}/custom_components/default_config_disabler/default_config_disabler.zip
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-41BDF5.svg)](https://github.com/hacs/integration)

Home Assistant integration to disable selected components from default_config.
See popular feature request at https://community.home-assistant.io/t/why-the-heck-is-default-config-so-difficult-to-customize/220112

Note: After a Home Assistant update this integration will re-disable selected components and automatically restart Home Assistant.

# Installation

## HACS
1. [Add](http://homeassistant.local:8123/hacs/integrations) custom integrations repository: https://github.com/tronikos/default_config_disabler
2. Select "Default Config Disabler" in the Integration tab and click download
3. Restart Home Assistant
4. Enable the integration

## Manual
1. Copy directory `custom_components/default_config_disabler` to your `<config dir>/custom_components` directory
2. Restart Home-Assistant
3. Enable the integration

## Enable the integration
1. Go to [Settings / Devices & Services / Integrations](http://homeassistant.local:8123/config/integrations). Click **+ ADD INTEGRATION**
2. Search for "Default Config Disabler" and click on it
3. Restart Home Assistant

# Configuration
1. Go to [Settings / Devices & Services / Integrations](http://homeassistant.local:8123/config/integrations)
2. Select "Default Config Disabler" and click on "Configure"
3. Select the default_config components you want to disable
63 changes: 63 additions & 0 deletions custom_components/default_config_disabler/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""The Default Config Disabler integration."""
from __future__ import annotations

import logging

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import SERVICE_HOMEASSISTANT_RESTART
from homeassistant.core import DOMAIN as HA_DOMAIN, HomeAssistant

from .const import CONF_COMPONENTS_TO_DISABLE
from .helpers import (
backup_original_default_config_manifest,
load_default_config_manifest,
load_original_default_config_manifest,
restore_original_default_config_manifest,
save_default_config_manifest,
)

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Default Config Disabler from a config entry."""
disabled_components = entry.options.get(CONF_COMPONENTS_TO_DISABLE, [])

backup_original_default_config_manifest()

new_manifest = load_original_default_config_manifest()
for disabled_component in disabled_components:
if disabled_component in new_manifest["dependencies"]:
new_manifest["dependencies"].remove(disabled_component)

current_manifest = load_default_config_manifest()

if new_manifest == current_manifest:
_LOGGER.info(
"Components: %s are already removed from default_config",
disabled_components,
)
else:
save_default_config_manifest(new_manifest)
_LOGGER.warning(
"Components: %s were removed from default_config", disabled_components
)
_LOGGER.warning("Restarting Home Assistant to use the updated default_config")
await hass.services.async_call(HA_DOMAIN, SERVICE_HOMEASSISTANT_RESTART)

entry.async_on_unload(entry.add_update_listener(update_listener))

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
if restore_original_default_config_manifest():
_LOGGER.warning("Restarting Home Assistant to use the original default_config")
await hass.services.async_call(HA_DOMAIN, SERVICE_HOMEASSISTANT_RESTART)
return True


async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Handle options update."""
await hass.config_entries.async_reload(entry.entry_id)
69 changes: 69 additions & 0 deletions custom_components/default_config_disabler/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Config flow for Default Config Disabler integration."""
from __future__ import annotations

from typing import Any

import voluptuous as vol

from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import config_validation as cv

from .const import CONF_COMPONENTS_TO_DISABLE, DOMAIN, NAME
from .helpers import get_default_config_components


class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Default Config Disabler."""

VERSION = 1

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")

if user_input is not None:
return self.async_create_entry(title=NAME, data=user_input)

return self.async_show_form(step_id="user", data_schema=vol.Schema({}))

@staticmethod
@callback
def async_get_options_flow(
config_entry: config_entries.ConfigEntry,
) -> config_entries.OptionsFlow:
"""Create the options flow."""
return OptionsFlowHandler(config_entry)


class OptionsFlowHandler(config_entries.OptionsFlow):
"""Default Config Disabler options flow."""

def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
"""Initialize options flow."""
self.config_entry = config_entry

async def async_step_init(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Manage the options."""
if user_input is not None:
return self.async_create_entry(title="", data=user_input)

return self.async_show_form(
step_id="init",
data_schema=vol.Schema(
{
vol.Optional(
CONF_COMPONENTS_TO_DISABLE,
default=self.config_entry.options.get(
CONF_COMPONENTS_TO_DISABLE, []
),
): cv.multi_select(get_default_config_components()),
}
),
)
7 changes: 7 additions & 0 deletions custom_components/default_config_disabler/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Constants for the Default Config Disabler integration."""
from typing import Final

DOMAIN: Final = "default_config_disabler"
NAME: Final = "Default Config Disabler"

CONF_COMPONENTS_TO_DISABLE: Final = "components_to_disable"
57 changes: 57 additions & 0 deletions custom_components/default_config_disabler/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Helper functions for the Default Config Disabler integration."""
from __future__ import annotations

import json
import os
import shutil

import homeassistant.components as ha_components

DEFAULT_CONFIG_DIR = os.path.join(
os.path.dirname(os.path.realpath(ha_components.__file__)), "default_config"
)
DEFAULT_CONFIG_MANIFEST = os.path.join(DEFAULT_CONFIG_DIR, "manifest.json")
DEFAULT_CONFIG_MANIFEST_ORIGINAL = os.path.join(
DEFAULT_CONFIG_DIR, "manifest.original.json"
)


def backup_original_default_config_manifest() -> bool:
"""Backup default_config/manifest.json to manifest.original.json."""
if not os.path.exists(DEFAULT_CONFIG_MANIFEST_ORIGINAL):
shutil.copyfile(DEFAULT_CONFIG_MANIFEST, DEFAULT_CONFIG_MANIFEST_ORIGINAL)
return True
return False


def restore_original_default_config_manifest() -> bool:
"""Restore default_config/manifest.json from manifest.original.json."""
if os.path.exists(DEFAULT_CONFIG_MANIFEST_ORIGINAL):
shutil.copyfile(DEFAULT_CONFIG_MANIFEST_ORIGINAL, DEFAULT_CONFIG_MANIFEST)
os.remove(DEFAULT_CONFIG_MANIFEST_ORIGINAL)
return True
return False


def load_original_default_config_manifest() -> dict:
"""Load default_config/manifest.original.json."""
with open(DEFAULT_CONFIG_MANIFEST_ORIGINAL, encoding="utf-8") as f:
return json.load(f)


def load_default_config_manifest() -> dict:
"""Load default_config/manifest.json."""
with open(DEFAULT_CONFIG_MANIFEST, encoding="utf-8") as f:
return json.load(f)


def save_default_config_manifest(manifest: dict) -> None:
"""Save manifest to default_config/manifest.json."""
with open(DEFAULT_CONFIG_MANIFEST, "w", encoding="utf-8") as f:
json.dump(manifest, f, indent=2)


def get_default_config_components() -> list[str]:
"""Return a list of components in the default_config."""
backup_original_default_config_manifest()
return load_original_default_config_manifest()["dependencies"]
14 changes: 14 additions & 0 deletions custom_components/default_config_disabler/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"domain": "default_config_disabler",
"name": "Default Config Disabler",
"codeowners": [
"@tronikos"
],
"config_flow": true,
"dependencies": [],
"documentation": "https://github.com/tronikos/default_config_disabler",
"iot_class": "local_push",
"issue_tracker": "https://github.com/tronikos/default_config_disabler/issues",
"requirements": [],
"version": "0.0.0"
}
21 changes: 21 additions & 0 deletions custom_components/default_config_disabler/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"config": {
"step": {
"user": {
"description": "[%key:common::config_flow::description::confirm_setup%]"
}
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
}
},
"options": {
"step": {
"init": {
"data": {
"components_to_disable": "default_config components to disable"
}
}
}
}
}
21 changes: 21 additions & 0 deletions custom_components/default_config_disabler/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"config": {
"abort": {
"single_instance_allowed": "Already configured. Only a single configuration possible."
},
"step": {
"user": {
"description": "Do you want to start setup?"
}
}
},
"options": {
"step": {
"init": {
"data": {
"components_to_disable": "default_config components to disable"
}
}
}
}
}
7 changes: 7 additions & 0 deletions hacs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "Default Config Disabler",
"homeassistant": "2023.7.0",
"render_readme": true,
"zip_release": true,
"filename": "default_config_disabler.zip"
}

0 comments on commit 22b27cb

Please sign in to comment.