diff --git a/docker/Dockerfile.wheels b/docker/Dockerfile.wheels index a6fa222ec..19545dbcf 100644 --- a/docker/Dockerfile.wheels +++ b/docker/Dockerfile.wheels @@ -34,7 +34,8 @@ RUN pip3 wheel --wheel-dir=/wheels \ matplotlib \ click \ setproctitle \ - peewee + peewee \ + pymysql FROM scratch diff --git a/frigate/app.py b/frigate/app.py index bf593d6ac..73c66798c 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -13,6 +13,8 @@ import yaml from peewee_migrate import Router from playhouse.sqlite_ext import SqliteExtDatabase from playhouse.sqliteq import SqliteQueueDatabase +from peewee import MySQLDatabase +from playhouse.shortcuts import ReconnectMixin from pydantic import ValidationError from frigate.config import DetectorTypeEnum, FrigateConfig @@ -33,6 +35,8 @@ from frigate.watchdog import FrigateWatchdog logger = logging.getLogger(__name__) +class ReconnectMySQLDatabase(ReconnectMixin, MySQLDatabase): + pass class FrigateApp: def __init__(self): @@ -116,24 +120,40 @@ class FrigateApp: self.recordings_info_queue = mp.Queue() def init_database(self): - # Migrate DB location - old_db_path = os.path.join(CLIPS_DIR, "frigate.db") - if not os.path.isfile(self.config.database.path) and os.path.isfile( - old_db_path - ): - os.rename(old_db_path, self.config.database.path) + if self.config.database.type == "sqlite": + # Migrate DB location + old_db_path = os.path.join(CLIPS_DIR, "frigate.db") + if not os.path.isfile(self.config.database.path) and os.path.isfile( + old_db_path + ): + os.rename(old_db_path, self.config.database.path) - # Migrate DB schema - migrate_db = SqliteExtDatabase(self.config.database.path) + # Migrate DB schema + migrate_db = SqliteExtDatabase(self.config.database.path) - # Run migrations - del logging.getLogger("peewee_migrate").handlers[:] - router = Router(migrate_db) - router.run() + # Run migrations + del logging.getLogger("peewee_migrate").handlers[:] + router = Router(migrate_db) + router.run() - migrate_db.close() + migrate_db.close() + + self.db = SqliteQueueDatabase(self.config.database.path) + models = [Event, Recordings] + self.db.bind(models) + elif self.config.database.type == "mysql": + self.db = ReconnectMySQLDatabase(self.config.database.database, + host=self.config.database.host, + port=self.config.database.port, + user=self.config.database.user, + passwd=self.config.database.password + ) + models = [Event, Recordings] + self.db.bind(models) + + Event.create_table() + Recordings.create_table() - self.db = SqliteQueueDatabase(self.config.database.path) models = [Event, Recordings] self.db.bind(models) diff --git a/frigate/config.py b/frigate/config.py index e89b43003..cd5dd2693 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -644,12 +644,36 @@ class CameraConfig(FrigateBaseModel): return [part for part in cmd if part != ""] +class DatabaseTypeEnum(str, Enum): + sqlite = "sqlite" + mysql = "mysql" class DatabaseConfig(FrigateBaseModel): + type: DatabaseTypeEnum = Field( + default=DatabaseTypeEnum.sqlite, title="Database connection method, sqlite, mysql" + ) + + # Only used for sqlite path: str = Field( default=os.path.join(BASE_DIR, "frigate.db"), title="Database path." ) + # Only used for mysql + database: str = Field( + default="frigate", title="Database name." + ) + host: str = Field( + default="localhost", title="Database host." + ) + user: str = Field( + default="frigate", title="Database user." + ) + password: str = Field( + default="frigate", title="Database password." + ) + port: int = Field( + default=3306, title="Database password." + ) class ModelConfig(FrigateBaseModel): path: Optional[str] = Field(title="Custom Object detection model path.") diff --git a/frigate/models.py b/frigate/models.py index 35a397f5c..b42dc35c1 100644 --- a/frigate/models.py +++ b/frigate/models.py @@ -1,6 +1,7 @@ from numpy import unique from peewee import * from playhouse.sqlite_ext import * +from playhouse.mysql_ext import * class Event(Model): @@ -8,7 +9,7 @@ class Event(Model): label = CharField(index=True, max_length=20) camera = CharField(index=True, max_length=20) start_time = DateTimeField() - end_time = DateTimeField() + end_time = DateTimeField(null=True) top_score = FloatField() false_positive = BooleanField() zones = JSONField()