mirror of
https://github.com/ferdzo/iotDashboard.git
synced 2026-04-05 09:06:26 +00:00
Added multi-protocol support for devices, improved models and updated readme.md and instructions
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""add protocol and connection_config to devices
|
||||
|
||||
Revision ID: 4e405f1129b1
|
||||
Revises: 4f152b34e800
|
||||
Create Date: 2025-11-01 19:07:22.800918+00:00
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '4e405f1129b1'
|
||||
down_revision: Union[str, Sequence[str], None] = '4f152b34e800'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('device_credentials',
|
||||
sa.Column('id', sa.Text(), nullable=False),
|
||||
sa.Column('device_id', sa.Text(), nullable=False),
|
||||
sa.Column('credential_type', sa.Text(), nullable=False),
|
||||
sa.Column('credential_hash', sa.Text(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column('expires_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('revoked_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['device_id'], ['devices.id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index('idx_device_credentials_active', 'device_credentials', ['device_id', 'revoked_at'], unique=False)
|
||||
op.create_index('idx_device_credentials_device_id', 'device_credentials', ['device_id'], unique=False)
|
||||
|
||||
# Add protocol column as nullable first, set default for existing rows, then make NOT NULL
|
||||
op.add_column('devices', sa.Column('protocol', sa.Text(), nullable=True))
|
||||
op.execute("UPDATE devices SET protocol = 'mqtt' WHERE protocol IS NULL")
|
||||
op.alter_column('devices', 'protocol', nullable=False)
|
||||
|
||||
op.add_column('devices', sa.Column('connection_config', sa.JSON(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('devices', 'connection_config')
|
||||
op.drop_column('devices', 'protocol')
|
||||
op.drop_index('idx_device_credentials_device_id', table_name='device_credentials')
|
||||
op.drop_index('idx_device_credentials_active', table_name='device_credentials')
|
||||
op.drop_table('device_credentials')
|
||||
# ### end Alembic commands ###
|
||||
@@ -8,7 +8,7 @@ To modify schema:
|
||||
4. Run: alembic upgrade head
|
||||
"""
|
||||
|
||||
from sqlalchemy import Boolean, Column, Float, ForeignKey, Index, Text, DateTime
|
||||
from sqlalchemy import Boolean, Column, Float, ForeignKey, Index, Text, DateTime, JSON
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
@@ -23,13 +23,13 @@ class Device(Base):
|
||||
id = Column(Text, primary_key=True)
|
||||
name = Column(Text, nullable=False)
|
||||
location = Column(Text)
|
||||
protocol = Column(Text, nullable=False, default="mqtt")
|
||||
connection_config = Column(JSON)
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Device(id={self.id}, name={self.name})>"
|
||||
|
||||
|
||||
return f"<Device(id={self.id}, name={self.name}, protocol={self.protocol})>"
|
||||
class DeviceCertificate(Base):
|
||||
"""X.509 certificates issued to devices for mTLS authentication."""
|
||||
|
||||
@@ -40,7 +40,7 @@ class DeviceCertificate(Base):
|
||||
Text, ForeignKey("devices.id", ondelete="CASCADE"), nullable=False
|
||||
)
|
||||
certificate_pem = Column(Text, nullable=False)
|
||||
private_key_pem = Column(Text) # Optional: for backup/escrow
|
||||
private_key_pem = Column(Text)
|
||||
issued_at = Column(DateTime(timezone=True), nullable=False)
|
||||
expires_at = Column(DateTime(timezone=True), nullable=False)
|
||||
revoked_at = Column(DateTime(timezone=True))
|
||||
@@ -54,6 +54,30 @@ class DeviceCertificate(Base):
|
||||
return f"<DeviceCertificate(id={self.id}, device_id={self.device_id}, expires={self.expires_at})>"
|
||||
|
||||
|
||||
class DeviceCredential(Base):
|
||||
"""Authentication credentials for non-mTLS protocols (HTTP, webhook, etc)."""
|
||||
|
||||
__tablename__ = "device_credentials"
|
||||
|
||||
id = Column(Text, primary_key=True)
|
||||
device_id = Column(
|
||||
Text, ForeignKey("devices.id", ondelete="CASCADE"), nullable=False
|
||||
)
|
||||
credential_type = Column(Text, nullable=False)
|
||||
credential_hash = Column(Text, nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), nullable=False)
|
||||
expires_at = Column(DateTime(timezone=True))
|
||||
revoked_at = Column(DateTime(timezone=True))
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_device_credentials_device_id", "device_id"),
|
||||
Index("idx_device_credentials_active", "device_id", "revoked_at"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<DeviceCredential(id={self.id}, device_id={self.device_id}, type={self.credential_type})>"
|
||||
|
||||
|
||||
class Telemetry(Base):
|
||||
"""
|
||||
Time-series telemetry data from devices.
|
||||
|
||||
Reference in New Issue
Block a user