-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Dmitry Mamontov
committed
Jan 16, 2022
0 parents
commit b8c043c
Showing
16 changed files
with
1,168 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
name: Validate | ||
|
||
on: | ||
push: | ||
pull_request: | ||
|
||
jobs: | ||
validate: | ||
runs-on: "ubuntu-latest" | ||
steps: | ||
- uses: "actions/checkout@v2" | ||
- name: HACS validation | ||
uses: "hacs/action@main" | ||
with: | ||
category: "integration" | ||
ignore: brands topics |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
pip-wheel-metadata/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||
__pypackages__/ | ||
|
||
# Celery stuff | ||
celerybeat-schedule | ||
celerybeat.pid | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ | ||
|
||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# Systemd Manager for Home Assistant | ||
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs) | ||
[![donate paypal](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://paypal.me/dslonyara) | ||
[![donate tinkoff](https://img.shields.io/badge/Donate-Tinkoff-yellow.svg)](https://www.tinkoff.ru/sl/3FteV5DtBOV) | ||
|
||
The component allows you to manage systemd services via [D-Bus](https://www.freedesktop.org/wiki/Software/dbus/) | ||
|
||
## Table of Contents | ||
- [Prerequisites](#prerequisites) | ||
- [Install](#install) | ||
- [Config](#config) | ||
- [Advanced config](#advanced-config) | ||
- [Services](#services) | ||
- [Performance table](#performance-table) | ||
|
||
## Prerequisites | ||
#### Ubuntu | ||
1. This component uses `D-Bus` to control `systemd`. You need to have D-Bus itself and its python bindings in order to use this component: | ||
```shell | ||
sudo apt install dbus libdbus-glib-1-dev libdbus-1-dev python-dbus | ||
``` | ||
|
||
2. You also need to set up a `polkit` rule so that your user can control systemd via D-Bus. To do this, run the command and paste the content: | ||
```shell | ||
sudo nano /etc/polkit-1/localauthority/50-local.d/systemd-manager.pkla | ||
``` | ||
```ini | ||
[Allow user systemd-manager to execute systemctl commands] | ||
Identity=unix-user:<your user from which hass is executed.> | ||
Action=org.freedesktop.systemd1.manage-units | ||
ResultAny=yes | ||
``` | ||
#### Other | ||
Not yet tested | ||
|
||
## Install | ||
Installed through the custom repository [HACS](https://hacs.xyz/) - `dmamontov/hass-systemd-manager` | ||
|
||
Or by copying the `systemd_manager` folder from [the latest release](https://github.com/dmamontov/hass-systemd-manager/releases/latest) to the custom_components folder (create if necessary) of the configs directory. | ||
|
||
## Config | ||
#### Via GUI (Only) | ||
|
||
`Settings` > `Integrations` > `Plus` > `Systemd Manager` | ||
|
||
All you have to do is select the systemd services you want to manage. | ||
|
||
#### Warnings | ||
1. Only one configuration is allowed; | ||
2. Do not select all services, this increases the load on the processor, especially D-Bus; | ||
|
||
## Advanced config | ||
To get the status of the services, the component requests the status of the services every 10 seconds. This value can be changed in the component's settings. | ||
|
||
## Services | ||
All services support only entity_id. | ||
|
||
[Mode detail](https://www.freedesktop.org/wiki/Software/systemd/dbus/) | ||
|
||
**start** | ||
```yaml | ||
service: systemd_manager.start | ||
data: | ||
mode: REPLACE # One of REPLACE, FAIL, ISOLATE, IGNORE_DEPENDENCIES, IGNORE_REQUIREMENTS | ||
target: | ||
entity_id: switch.systemd_... | ||
``` | ||
**stop** | ||
```yaml | ||
service: systemd_manager.stop | ||
data: | ||
mode: REPLACE # One of REPLACE, FAIL, IGNORE_DEPENDENCIES, IGNORE_REQUIREMENTS | ||
target: | ||
entity_id: switch.systemd_... | ||
``` | ||
**restart** | ||
```yaml | ||
service: systemd_manager.restart | ||
data: | ||
mode: REPLACE # One of REPLACE, FAIL, IGNORE_DEPENDENCIES, IGNORE_REQUIREMENTS | ||
target: | ||
entity_id: switch.systemd_... | ||
``` | ||
**enable** | ||
```yaml | ||
service: systemd_manager.enable | ||
target: | ||
entity_id: switch.systemd_... | ||
``` | ||
**disable** | ||
```yaml | ||
service: systemd_manager.disable | ||
target: | ||
entity_id: switch.systemd_... | ||
``` | ||
## Performance table | ||
![](table.png) | ||
1. Install [Flex Table](https://github.com/custom-cards/flex-table-card) from HACS | ||
2. Add new Lovelace tab with **Panel Mode** | ||
3. Add new Lovelace card: | ||
- [example](https://gist.github.com/dmamontov/e8c52c129fb19fca633d0d2d779676e3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import logging | ||
|
||
from homeassistant.core import HomeAssistant, ServiceCall | ||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry | ||
|
||
from .core.const import ( | ||
DOMAIN, | ||
CONF_MODE, | ||
SERVICE_START, | ||
SERVICE_STOP, | ||
SERVICE_RESTART, | ||
SERVICE_ENABLE, | ||
SERVICE_DISABLE, | ||
ATTR_UNIT_NAME | ||
) | ||
from .core.worker import Worker | ||
from .core.manager import Mode | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
async def async_setup(hass: HomeAssistant, config: dict) -> bool: | ||
await async_init_services(hass) | ||
|
||
if DOMAIN not in config: | ||
return True | ||
|
||
if DOMAIN in hass.data: | ||
return False | ||
|
||
hass.data.setdefault(DOMAIN, {}) | ||
|
||
hass.async_create_task(hass.config_entries.flow.async_init( | ||
DOMAIN, context = {'source': SOURCE_IMPORT}, data = config | ||
)) | ||
|
||
return True | ||
|
||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: | ||
if config_entry.data: | ||
hass.config_entries.async_update_entry(config_entry, data = {} , options = config_entry.data) | ||
|
||
worker = Worker(hass, config_entry) | ||
|
||
hass.data.setdefault(DOMAIN, worker) | ||
|
||
if not await worker.async_setup(): | ||
return False | ||
|
||
return True | ||
|
||
async def async_init_services(hass: HomeAssistant) -> None: | ||
async def service_start(service_call: ServiceCall) -> None: | ||
await async_call_action(hass, SERVICE_START, dict(service_call.data)) | ||
|
||
async def service_stop(service_call: ServiceCall) -> None: | ||
await async_call_action(hass, SERVICE_STOP, dict(service_call.data)) | ||
|
||
async def service_restart(service_call: ServiceCall) -> None: | ||
await async_call_action(hass, SERVICE_RESTART, dict(service_call.data)) | ||
|
||
async def service_enable(service_call: ServiceCall) -> None: | ||
await async_call_action(hass, SERVICE_ENABLE, dict(service_call.data)) | ||
|
||
async def service_disable(service_call: ServiceCall) -> None: | ||
await async_call_action(hass, SERVICE_DISABLE, dict(service_call.data)) | ||
|
||
hass.services.async_register(DOMAIN, SERVICE_START, service_start) | ||
hass.services.async_register(DOMAIN, SERVICE_STOP, service_stop) | ||
hass.services.async_register(DOMAIN, SERVICE_RESTART, service_restart) | ||
hass.services.async_register(DOMAIN, SERVICE_ENABLE, service_enable) | ||
hass.services.async_register(DOMAIN, SERVICE_DISABLE, service_disable) | ||
|
||
async def async_call_action(hass: HomeAssistant, action: str, data: dict) -> None: | ||
entities = data.pop('entity_id', None) | ||
|
||
if not entities: | ||
return | ||
|
||
mode = data.pop(CONF_MODE, None) | ||
if mode: | ||
mode = Mode[mode] | ||
|
||
manager = hass.data[DOMAIN].manager | ||
|
||
for entity_id in entities: | ||
state = hass.states.get(entity_id) | ||
if not state: | ||
continue | ||
|
||
unit_name = state.attributes[ATTR_UNIT_NAME] | ||
|
||
if action == SERVICE_START: | ||
manager.start(unit_name, mode) | ||
return | ||
|
||
if action == SERVICE_STOP: | ||
manager.stop(unit_name, mode) | ||
return | ||
|
||
if action == SERVICE_RESTART: | ||
manager.restart(unit_name, mode) | ||
return | ||
|
||
if action == SERVICE_ENABLE: | ||
manager.enable(unit_name) | ||
return | ||
|
||
if action == SERVICE_DISABLE: | ||
manager.disable(unit_name) | ||
return |
Oops, something went wrong.