Files
home-automation/alembic_app/versions/20260624_12_dsmr_decouple_telegram_id.py
T

59 lines
2.5 KiB
Python
Raw Normal View History

"""decouple dsmr_reading from the telegram id
The DSMR Reader's own ``id`` field is auto-incrementing but is known to overflow
and require a manual reset to zero (a long-standing DSMR firmware quirk). If we
keep a UNIQUE constraint on ``source_id`` (the telegram id) and use it for
idempotency, an overflow/reset would make legitimately-new telegrams collide with
old ids and be silently dropped as "duplicates" — data loss.
This migration removes that coupling:
- Drops the UNIQUE constraint on ``source_id`` (the column is kept as a plain,
nullable reference value; it is no longer relied upon for uniqueness/dedup).
- Makes ``recorded_at`` (the telegram timestamp) UNIQUE instead — a single P1
meter emits one telegram per timestamp, so this is a robust, telegram-id-
independent idempotency key. The table's own autoincrement ``id`` PK remains
the stable internal identity.
Revision ID: 20260624_12_dsmr_decouple_telegram_id
Revises: 20260623_11_energy_tables
Create Date: 2026-06-24 00:00:00.000000
"""
from typing import Sequence, Union
from alembic import op
revision: str = "20260624_12_dsmr_decouple_telegram_id"
down_revision: Union[str, None] = "20260623_11_energy_tables"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# SQLite cannot ALTER away a constraint in place, so recreate the table via
# Alembic's batch mode. The table is recreated and rows are copied; existing
# data (if any) is preserved. recorded_at must be unique for this to succeed
# — a single meter never emits two telegrams at the exact same timestamp.
with op.batch_alter_table("dsmr_reading", schema=None) as batch_op:
# Old non-unique index on recorded_at is replaced by the unique constraint.
batch_op.drop_index("ix_dsmr_reading_recorded_at")
# Telegram id is no longer a uniqueness/idempotency key.
batch_op.drop_constraint("uq_dsmr_reading_source_id", type_="unique")
# Timestamp becomes the telegram-id-independent dedup key.
batch_op.create_unique_constraint(
"uq_dsmr_reading_recorded_at", ["recorded_at"]
)
def downgrade() -> None:
with op.batch_alter_table("dsmr_reading", schema=None) as batch_op:
batch_op.drop_constraint("uq_dsmr_reading_recorded_at", type_="unique")
batch_op.create_unique_constraint(
"uq_dsmr_reading_source_id", ["source_id"]
)
batch_op.create_index(
"ix_dsmr_reading_recorded_at", ["recorded_at"], unique=False
)