ipcam: start porting to new config and multiserver scheme
This commit is contained in:
parent
ba321657e0
commit
62ee71fdb0
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,7 +9,7 @@ __pycache__
|
||||
/include/test/test_inverter_monitor.log
|
||||
/youtrack-certificate
|
||||
/cpp
|
||||
/include/test.py
|
||||
/test/test.py
|
||||
/bin/test.py
|
||||
/arduino/ESP32CameraWebServer/wifi_password.h
|
||||
cmake-build-*
|
||||
|
@ -9,6 +9,7 @@ import __py_include
|
||||
|
||||
import homekit.telegram.aio as telegram
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from asyncio import Lock
|
||||
|
||||
@ -53,8 +54,8 @@ def get_all_cams() -> list:
|
||||
class IPCamServerDatabase(SQLiteBase):
|
||||
SCHEMA = 4
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def __init__(self, path=None):
|
||||
super().__init__(path=path)
|
||||
|
||||
def schema_init(self, version: int) -> None:
|
||||
cursor = self.cursor()
|
||||
@ -319,9 +320,9 @@ class IPCamWebServer(http.HTTPServer):
|
||||
# other global stuff
|
||||
# ------------------
|
||||
|
||||
def open_database():
|
||||
def open_database(database_path: str):
|
||||
global db
|
||||
db = IPCamServerDatabase()
|
||||
db = IPCamServerDatabase(database_path)
|
||||
|
||||
# update cams list in database, if needed
|
||||
cams = db.get_all_timestamps().keys()
|
||||
@ -558,9 +559,12 @@ logger = logging.getLogger(__name__)
|
||||
# --------------------
|
||||
|
||||
if __name__ == '__main__':
|
||||
config.load_app('ipcam_server')
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('--listen', type=str, required=True)
|
||||
parser.add_argument('--database-path', type=str, required=True)
|
||||
arg = config.load_app(no_config=True, parser=parser)
|
||||
|
||||
open_database()
|
||||
open_database(arg.database_path)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
82
include/py/homekit/camera/config.py
Normal file
82
include/py/homekit/camera/config.py
Normal file
@ -0,0 +1,82 @@
|
||||
from ..config import ConfigUnit, LinuxBoardsConfig
|
||||
from typing import Optional
|
||||
from .types import CameraType, VideoContainerType, VideoCodecType
|
||||
|
||||
|
||||
_lbc = LinuxBoardsConfig()
|
||||
|
||||
|
||||
def _validate_roi_line(field, value, error) -> bool:
|
||||
p = value.split(' ')
|
||||
if len(p) != 4:
|
||||
error(field, f'{field}: must contain four coordinates separated by space')
|
||||
for n in p:
|
||||
if not n.isnumeric():
|
||||
error(field, f'{field}: invalid coordinates (not a number)')
|
||||
return True
|
||||
|
||||
|
||||
class IpcamConfig(ConfigUnit):
|
||||
NAME = 'ipcam'
|
||||
|
||||
@classmethod
|
||||
def schema(cls) -> Optional[dict]:
|
||||
lbc = LinuxBoardsConfig()
|
||||
return {
|
||||
'cams': {
|
||||
'type': 'dict',
|
||||
'keysrules': {'type': ['string', 'integer']},
|
||||
'valuesrules': {
|
||||
'type': 'dict',
|
||||
'schema': {
|
||||
'type': {'type': 'string', 'allowed': [t.value for t in CameraType], 'required': True},
|
||||
'codec': {'type': 'string', 'allowed': [t.value for t in VideoCodecType], 'required': True},
|
||||
'container': {'type': 'string', 'allowed': [t.value for t in VideoContainerType], 'required': True},
|
||||
'server': {'type': 'string', 'allowed': list(lbc.get().keys()), 'required': True},
|
||||
'disk': {'type': 'integer', 'required': True},
|
||||
'motion': {
|
||||
'type': 'dict',
|
||||
'schema': {
|
||||
'threshold': {'type': ['float', 'integer']},
|
||||
'roi': {
|
||||
'type': 'list',
|
||||
'schema': {'type': 'string', 'check_with': _validate_roi_line}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'motion_padding': {'type': 'integer', 'required': True},
|
||||
'motion_telegram': {'type': 'boolean', 'required': True},
|
||||
'fix_interval': {'type': 'integer', 'required': True},
|
||||
'fix_enabled': {'type': 'boolean', 'required': True},
|
||||
'cleanup_min_gb': {'type': 'integer', 'required': True},
|
||||
'cleanup_interval': {'type': 'integer', 'required': True},
|
||||
|
||||
# TODO FIXME
|
||||
'fragment_url_templates': cls._url_templates_schema(),
|
||||
'original_file_url_templates': cls._url_templates_schema()
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def custom_validator(data):
|
||||
for n, cam in data['cams'].items():
|
||||
linux_box = _lbc[cam['server']]
|
||||
if 'ext_hdd' not in linux_box:
|
||||
raise ValueError(f'cam-{n}: linux box {cam["server"]} must have ext_hdd defined')
|
||||
disk = cam['disk']-1
|
||||
if disk < 0 or disk >= len(linux_box['ext_hdd']):
|
||||
raise ValueError(f'cam-{n}: invalid disk index for linux box {cam["server"]}')
|
||||
|
||||
@classmethod
|
||||
def _url_templates_schema(cls) -> dict:
|
||||
return {
|
||||
'type': 'list',
|
||||
'empty': False,
|
||||
'schema': {
|
||||
'type': 'list',
|
||||
'empty': False,
|
||||
'schema': {'type': 'string'}
|
||||
}
|
||||
}
|
@ -3,3 +3,15 @@ from enum import Enum
|
||||
|
||||
class CameraType(Enum):
|
||||
ESP32 = 'esp32'
|
||||
ALIEXPRESS_NONAME = 'ali'
|
||||
HIKVISION = 'hik'
|
||||
|
||||
|
||||
class VideoContainerType(Enum):
|
||||
MP4 = 'mp4'
|
||||
MOV = 'mov'
|
||||
|
||||
|
||||
class VideoCodecType(Enum):
|
||||
H264 = 'h264'
|
||||
H265 = 'h265'
|
||||
|
@ -158,6 +158,9 @@ class ConfigUnit(BaseConfigUnit):
|
||||
else:
|
||||
normalized = v.validated(self._data, schema)
|
||||
|
||||
if not normalized:
|
||||
raise cerberus.DocumentError(f'validation failed: {v.errors}')
|
||||
|
||||
self._data = normalized
|
||||
|
||||
try:
|
||||
|
@ -15,10 +15,13 @@ def _get_database_path(name: str) -> str:
|
||||
class SQLiteBase:
|
||||
SCHEMA = 1
|
||||
|
||||
def __init__(self, name=None, check_same_thread=False):
|
||||
if name is None:
|
||||
def __init__(self, name=None, path=None, check_same_thread=False):
|
||||
if not path:
|
||||
if not name:
|
||||
name = config.app_config['database_name']
|
||||
database_path = _get_database_path(name)
|
||||
else:
|
||||
database_path = path
|
||||
if not os.path.exists(os.path.dirname(database_path)):
|
||||
os.makedirs(os.path.dirname(database_path))
|
||||
|
||||
|
2
misc/home_linux_boards/etc/default/homekit_ipcam_server
Normal file
2
misc/home_linux_boards/etc/default/homekit_ipcam_server
Normal file
@ -0,0 +1,2 @@
|
||||
LISTEN="0.0.0.0:8320"
|
||||
DATABASE_PATH="/data1/ipcam_server.db"
|
@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=HomeKit IPCam Server
|
||||
Description=Homekit IPCam Server
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
@ -7,7 +7,8 @@ User=user
|
||||
Group=user
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
ExecStart=/home/user/homekit/bin/ipcam_server.py
|
||||
EnvironmentFile=/etc/default/homekit_ipcam_server
|
||||
ExecStart=/home/user/homekit/bin/ipcam_server.py --listen "$LISTEN" --database-path "$DATABASE_PATH"
|
||||
WorkingDirectory=/home/user
|
||||
|
||||
[Install]
|
||||
|
@ -1,8 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
import __py_include
|
||||
from homekit.relay import RelayClient
|
||||
|
||||
from pprint import pprint
|
||||
from homekit.camera.config import IpcamConfig
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
c = RelayClient()
|
||||
print(c, c._host)
|
||||
c = IpcamConfig()
|
||||
pprint(c.get())
|
Loading…
x
Reference in New Issue
Block a user