Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bd30ba9
docs: add missing docstrings in coordinator.py
bastgau Feb 19, 2026
1a62ca0
docs: add missing docstrings in device_info.py
bastgau Feb 19, 2026
ef20e33
docs: add missing docstrings in helpers.py
bastgau Feb 19, 2026
7a837d2
docs: add missing docstrings in services.py
bastgau Feb 19, 2026
cb1fe8d
docs: fix empty docstrings in clouding.py
bastgau Feb 19, 2026
6ae435d
docs: fix empty docstrings in models.py
bastgau Feb 19, 2026
bc25d30
docs: fix empty docstring in config_flow.py
bastgau Feb 19, 2026
ca3b9b0
Merge pull request #13 from bastgau/docs/fix-empty-docstrings
bastgau Feb 19, 2026
3de1ee7
docs: complete incomplete docstrings in config_flow.py
bastgau Feb 19, 2026
2805719
docs: complete get_servers docstring with Returns and Raises
bastgau Feb 19, 2026
0748958
fix: code quality issues from code review
bastgau Feb 19, 2026
8d6de84
fix: add blank line after raises section
bastgau Feb 19, 2026
b842ea3
fix: remove import unused
bastgau Feb 19, 2026
bd56494
chore: add AI tools configuration and improve script configuration
bastgau Feb 23, 2026
2ec9bb3
chore: missing title in setup script
bastgau Feb 23, 2026
5da770e
chore: change ollama IP
bastgau Feb 23, 2026
50b5750
refactor: add Pylance/Pyright strict type checking support
bastgau Feb 23, 2026
bc91071
fix: address code quality issues from analysis
bastgau Feb 24, 2026
fe16083
docs: fix missing and incomplete docstrings across modules
bastgau Feb 24, 2026
1dd2b85
docs: add type annotations
bastgau Feb 25, 2026
6c1d896
refactor: improve type hints and error handling in clouding component
bastgau Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .devcontainer/.env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OPENROUTER_API_KEY="your-key"
3 changes: 2 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ RUN \
uuid-dev \
webp \
xz-utils \
zlib1g-dev
zlib1g-dev \
vim
5 changes: 5 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
"eamodio.gitlens"
],
"settings": {
"files.insertFinalNewline": true,
"files.exclude": {
".ruff_cache": true,
"**/__pycache__": true
},
"files.eol": "\n",
"editor.tabSize": 4,
"python.pythonPath": "/usr/bin/python3",
Expand Down
153 changes: 145 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,153 @@
# artifacts
__pycache__
.pytest*
*.egg-info
*/build/*
*/dist/*
# macOS
.DS_Store
.AppleDouble
.LSOverride

# Thumbnails
._*

# 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

# misc
# 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/
cover/

# 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
.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-O-Toole/prodigy
__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/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# Developper settings (vscode)
**/.vscode/settings.json
.orcommit.json
.opencommit

# Home Assistant configuration
config/*
.DS_Store
23 changes: 23 additions & 0 deletions .opencommit-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
OCO_API_URL=http://host.docker.internal:11434/api/chat
OCO_MODEL=deepseek-coder:6.7b
OCO_API_KEY=undefined
OCO_API_CUSTOM_HEADERS=undefined
OCO_AI_PROVIDER=ollama
OCO_TOKENS_MAX_INPUT=4096
OCO_TOKENS_MAX_OUTPUT=500
OCO_DESCRIPTION=false
OCO_EMOJI=false
OCO_LANGUAGE=en
OCO_MESSAGE_TEMPLATE_PLACEHOLDER=$msg
OCO_PROMPT_MODULE=conventional-commit
OCO_ONE_LINE_COMMIT=true
OCO_TEST_MOCK_TYPE=commit-message
OCO_OMIT_SCOPE=true
OCO_GITPUSH=false
OCO_WHY=false
OCO_HOOK_AUTO_UNCOMMENT=false

# OCO_AI_PROVIDER=openai
# OCO_API_URL=https://openrouter.ai/api/v1/
# OCO_MODEL=arcee-ai/trinity-large-preview:free
# OCO_API_KEY="xxxxxx"
24 changes: 24 additions & 0 deletions .orcommit.json-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"providers": {
"openrouter": {
"baseUrl": "https://openrouter.ai/api/v1",
"timeout": 60000,
"apiKey": "xxxxx",
"model": "arcee-ai/trinity-large-preview:free"
},
"openai": {
"baseUrl": "https://api.openai.com/v1",
"timeout": 60000
}
},
"preferences": {
"defaultProvider": "openrouter",
"maxTokens": 500,
"temperature": 0.8,
"autoConfirm": false,
"language": "en",
"commitFormat": "conventional",
"maxCommitLength": 800
},
"version": "1.0.0"
}
48 changes: 40 additions & 8 deletions custom_components/clouding/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from datetime import timedelta
import logging
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

from homeassistant.const import Platform

Expand All @@ -23,7 +23,6 @@
CloudingConfigEntry,
CloudingDataUpdateCoordinator,
)
from .helpers import purge_entities
from .services import (
async_archive_server,
async_hard_reboot_server,
Expand All @@ -34,14 +33,16 @@
)

if TYPE_CHECKING:
from collections.abc import Callable, Coroutine, Mapping

from homeassistant.core import HomeAssistant, ServiceCall

PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Platform.SENSOR,
]

_SERVICE_MAP = {
_SERVICE_MAP: dict[str, Callable[[ServiceCall, Mapping[str, Any]], Coroutine[Any, Any, None]]] = {
SERVICE_ARCHIVE_SERVER: async_archive_server,
SERVICE_UNARCHIVE_SERVER: async_unarchive_server,
SERVICE_HARD_REBOOT_SERVER: async_hard_reboot_server,
Expand All @@ -54,10 +55,24 @@


async def async_setup_entry(hass: HomeAssistant, config_entry: CloudingConfigEntry) -> bool:
"""Set up Clouding.io from a config entry."""
"""Set up Clouding.io from a config entry.

Args:
hass (HomeAssistant): The Home Assistant instance.
config_entry (CloudingConfigEntry): The Clouding.io config entry.

Returns:
bool: True if the setup was successful.

Raises:
ConfigEntryNotReady: If the first data refresh fails.

"""

conf_update_interval: int | None = config_entry.data.get(CONF_UPDATE_INTERVAL)

update_interval: timedelta

if conf_update_interval is None:
update_interval = MIN_TIME_BETWEEN_UPDATES
else:
Expand All @@ -76,20 +91,37 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: CloudingConfigEnt

# Register services to hass
async def execute_service(call: ServiceCall) -> None:
"""Execute a service to Clouding.io."""
"""Execute a service to Clouding.io.

function_call = _SERVICE_MAP[call.service]
Args:
call (ServiceCall): The Home Assistant service call object.

Returns:
None.

"""

function_call: Callable[[ServiceCall, Mapping[str, Any]], Coroutine[Any, Any, None]] = _SERVICE_MAP[call.service]
await function_call(call, call.data)

for service in _SERVICE_MAP:
hass.services.async_register(DOMAIN, service, execute_service)

# purge_entities(config_entry, hass)
# (@bastgau) call purge_entities(config_entry, hass) here to remove stale devices (not yet implemented)

return True


async def async_unload_entry(hass: HomeAssistant, entry: CloudingConfigEntry) -> bool:
"""Unload a config entry."""
"""Unload a config entry.

Args:
hass (HomeAssistant): The Home Assistant instance.
entry (CloudingConfigEntry): The Clouding.io config entry to unload.

Returns:
bool: True if the unload was successful.

"""

return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
Loading