Compare commits
1 Commits
v2.0.0-alp
...
v2.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
| 1336bc36fa |
13
README.md
13
README.md
@@ -22,6 +22,18 @@ pip install -e ".[dev]"
|
||||
uvicorn app.main:app --reload
|
||||
```
|
||||
|
||||
## Home Assistant Add-on
|
||||
|
||||
Add this repository in Home Assistant:
|
||||
|
||||
```text
|
||||
http://192.168.6.31:3000/Otto/sillyhome-future
|
||||
```
|
||||
|
||||
Then install **SillyHome Future**. The add-on is intentionally independent from
|
||||
`sillyhome-next` and starts its own v2 event-core API on port `8099` behind
|
||||
Ingress.
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
@@ -29,4 +41,3 @@ pytest
|
||||
ruff check .
|
||||
mypy app tests
|
||||
```
|
||||
|
||||
|
||||
14
addon/Dockerfile
Normal file
14
addon/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM python:3.13-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY pyproject.toml README.md ./
|
||||
COPY app ./app
|
||||
RUN python -m pip install --no-cache-dir .
|
||||
|
||||
COPY addon/run.sh /run.sh
|
||||
RUN chmod 0755 /run.sh \
|
||||
&& useradd --create-home --uid 10001 sillyhome
|
||||
|
||||
ENTRYPOINT ["/run.sh"]
|
||||
|
||||
29
addon/config.yaml
Normal file
29
addon/config.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
name: SillyHome Future
|
||||
version: "2.0.0-alpha.2"
|
||||
slug: sillyhome_future
|
||||
description: Event-first SillyHome v2 test controller
|
||||
url: http://192.168.6.31:3000/Otto/sillyhome-future
|
||||
arch:
|
||||
- amd64
|
||||
startup: application
|
||||
boot: manual
|
||||
watchdog: http://[HOST]:[PORT:8099]/health
|
||||
init: false
|
||||
ingress: true
|
||||
ingress_port: 8099
|
||||
panel_title: SillyHome Future
|
||||
panel_icon: mdi:home-lightning-bolt
|
||||
panel_admin: true
|
||||
homeassistant_api: true
|
||||
hassio_api: false
|
||||
auth_api: false
|
||||
map:
|
||||
- type: addon_config
|
||||
read_only: false
|
||||
options:
|
||||
store_path: /data/future_store
|
||||
log_level: info
|
||||
schema:
|
||||
store_path: str
|
||||
log_level: list(debug|info|warning|error)
|
||||
|
||||
31
addon/run.sh
Normal file
31
addon/run.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
export PYTHONUNBUFFERED=1
|
||||
|
||||
STORE_PATH="/data/future_store"
|
||||
LOG_LEVEL="info"
|
||||
if [ -f /data/options.json ]; then
|
||||
eval "$(python - <<'PY'
|
||||
import json
|
||||
import shlex
|
||||
|
||||
with open("/data/options.json", encoding="utf-8") as stream:
|
||||
options = json.load(stream)
|
||||
for name, env_name in {
|
||||
"store_path": "STORE_PATH",
|
||||
"log_level": "LOG_LEVEL",
|
||||
}.items():
|
||||
if name in options:
|
||||
print(f"{env_name}={shlex.quote(str(options[name]))}")
|
||||
PY
|
||||
)"
|
||||
fi
|
||||
|
||||
export SILLYHOME_FUTURE_STORE="$STORE_PATH"
|
||||
mkdir -p "$SILLYHOME_FUTURE_STORE"
|
||||
chown -R sillyhome:sillyhome "$SILLYHOME_FUTURE_STORE"
|
||||
|
||||
exec su -s /bin/sh sillyhome -c \
|
||||
"uvicorn app.main:app --host 0.0.0.0 --port 8099 --log-level ${LOG_LEVEL}"
|
||||
|
||||
@@ -21,7 +21,7 @@ from app.core.stores import FutureStores
|
||||
app = FastAPI(
|
||||
title="SillyHome Future API",
|
||||
description="SillyHome v2 event-core side project.",
|
||||
version="2.0.0-alpha.1",
|
||||
version="2.0.0-alpha.2",
|
||||
)
|
||||
stores = FutureStores(os.getenv("SILLYHOME_FUTURE_STORE", ".future_store"))
|
||||
event_core = EventCore(stores)
|
||||
@@ -110,4 +110,3 @@ def export_backup() -> BackupBundle:
|
||||
def restore_backup(bundle: BackupBundle) -> dict[str, str]:
|
||||
stores.restore_backup(bundle)
|
||||
return {"status": "restored"}
|
||||
|
||||
|
||||
@@ -27,3 +27,9 @@ state, but switching decisions must remain inspectable and testable.
|
||||
6. Dashboard v2
|
||||
7. Add-on hardening
|
||||
|
||||
## Add-on Contract
|
||||
|
||||
The Home Assistant add-on is owned by this repository and does not copy code
|
||||
from `sillyhome-next`. It starts the v2 API with `SILLYHOME_FUTURE_STORE`
|
||||
pointing at `/data/future_store`, so runtime, learning and control stores are
|
||||
kept inside the add-on data volume.
|
||||
|
||||
@@ -4,13 +4,14 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "sillyhome-future"
|
||||
version = "2.0.0-alpha.1"
|
||||
version = "2.0.0-alpha.2"
|
||||
description = "SillyHome v2 event-core prototype"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"fastapi>=0.115",
|
||||
"pydantic>=2.8",
|
||||
"uvicorn[standard]>=0.30",
|
||||
"pyyaml>=6.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
@@ -32,4 +33,3 @@ target-version = "py311"
|
||||
python_version = "3.11"
|
||||
strict = true
|
||||
plugins = []
|
||||
|
||||
|
||||
4
repository.yaml
Normal file
4
repository.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
name: SillyHome Future Add-ons
|
||||
url: http://192.168.6.31:3000/Otto/sillyhome-future
|
||||
maintainer: Otto
|
||||
|
||||
21
tests/test_addon_config.py
Normal file
21
tests/test_addon_config.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import yaml # type: ignore[import-untyped]
|
||||
|
||||
|
||||
def test_addon_config_declares_future_addon() -> None:
|
||||
config = yaml.safe_load(Path("addon/config.yaml").read_text(encoding="utf-8"))
|
||||
|
||||
assert config["slug"] == "sillyhome_future"
|
||||
assert config["version"] == "2.0.0-alpha.2"
|
||||
assert config["ingress"] is True
|
||||
assert config["ingress_port"] == 8099
|
||||
assert config["homeassistant_api"] is True
|
||||
|
||||
|
||||
def test_repository_points_to_gitea_repo() -> None:
|
||||
repository = yaml.safe_load(Path("repository.yaml").read_text(encoding="utf-8"))
|
||||
|
||||
assert repository["url"] == "http://192.168.6.31:3000/Otto/sillyhome-future"
|
||||
@@ -15,8 +15,7 @@ def test_health_and_backup_roundtrip(tmp_path, monkeypatch) -> None: # type: ig
|
||||
|
||||
assert stores is not None
|
||||
assert health.status_code == 200
|
||||
assert health.json()["version"] == "2.0.0-alpha.1"
|
||||
assert health.json()["version"] == "2.0.0-alpha.2"
|
||||
assert backup.status_code == 200
|
||||
assert restore.status_code == 200
|
||||
assert restore.json() == {"status": "restored"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user