Replaces the read-only token and the webhook automation, which every install would have had to paste into its own Home Assistant. Connect now goes to Home Assistant's own sign-in page, and Steward keeps the refresh token that comes back, encrypted, and calls backup.create_automatic and update.install directly. The connection page warns that the stored credential has the same access as the user who signed in, and recommends a service account so Steward's actions are easy to tell apart in Home Assistant's logs. A user who isn't an administrator gets the status page and no Install. Those actions answer only when finished, so a request cut off once sent counts as sent and the outcome is read from the entities. Removing the connection, or signing in again, ends the old sign-in on Home Assistant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
43 lines
2.1 KiB
Python
43 lines
2.1 KiB
Python
"""Home Assistant: Steward holds a sign-in, in place of a token and a webhook
|
|
|
|
Revision ID: homeassistant_002_sign_in
|
|
Revises: homeassistant_001_connection
|
|
Create Date: 2026-10-31
|
|
"""
|
|
from typing import Sequence, Union
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision: str = "homeassistant_002_sign_in"
|
|
down_revision: Union[str, None] = "homeassistant_001_connection"
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
# A saved token can't be refreshed like a sign-in, so that connection signs in again.
|
|
op.execute("DELETE FROM homeassistant_connection")
|
|
op.drop_column("homeassistant_connection", "webhook_id")
|
|
op.drop_column("homeassistant_connection", "automation")
|
|
op.drop_column("homeassistant_updates", "triggered_before")
|
|
op.alter_column("homeassistant_connection", "token", new_column_name="refresh_token")
|
|
op.add_column("homeassistant_connection", sa.Column("client_id", sa.String(500), nullable=False))
|
|
op.add_column("homeassistant_connection",
|
|
sa.Column("can_install", sa.Boolean, nullable=False, server_default=sa.false()))
|
|
op.add_column("homeassistant_connection",
|
|
sa.Column("signed_in_by", sa.String(100), nullable=False, server_default=""))
|
|
op.add_column("homeassistant_connection", sa.Column("signed_in_at", sa.DateTime(timezone=True), nullable=True))
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.execute("DELETE FROM homeassistant_connection")
|
|
op.drop_column("homeassistant_connection", "signed_in_at")
|
|
op.drop_column("homeassistant_connection", "signed_in_by")
|
|
op.drop_column("homeassistant_connection", "can_install")
|
|
op.drop_column("homeassistant_connection", "client_id")
|
|
op.alter_column("homeassistant_connection", "refresh_token", new_column_name="token")
|
|
op.add_column("homeassistant_updates", sa.Column("triggered_before", sa.String(64), nullable=True))
|
|
op.add_column("homeassistant_connection", sa.Column("automation", sa.String(20), nullable=True))
|
|
op.add_column("homeassistant_connection", sa.Column("webhook_id", sa.Text, nullable=False))
|