use pydantic dataclasses, members are optional.. not the best

This commit is contained in:
2026-02-06 22:13:51 +01:00
parent 376fe69b9f
commit 501ba01bed
3 changed files with 102 additions and 90 deletions

View File

@@ -1,122 +1,128 @@
from projrequest import ProjectorConnection from projrequest import ProjectorConnection
from datetime import datetime from datetime import datetime
from pydantic import BaseModel
from typing import Dict, List, Any from typing import Dict, List, Any, ClassVar, Optional
from uuid import UUID from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
class BaseCommand(BaseModel): class BaseCommand(BaseModel):
projector: ProjectorConnection model_config = ConfigDict(arbitrary_types_allowed=True)
timestamp: datetime timestamp: datetime = datetime.now()
type: str type: str = ''
content: Any projector: ProjectorConnection = Field(exclude=True)
path: ClassVar[List[str]]
params: ClassVar[Dict[str, Any] | None] = None
def __init__(self, proj: ProjectorConnection) -> None: def update(self) -> List | Dict | None:
self.projector = proj resp = self.projector.get(path=self.path, params=self.params)
pass
def update(self, path: List[str], params: Dict[str, Any] | None = None):
resp = self.projector.get(path=path, params=params)
if resp is not None: if resp is not None:
self.timestamp = datetime.fromtimestamp(float(resp['timestamp'])) self.timestamp = datetime.fromtimestamp(float(resp['timestamp'])/1000)
self.type = resp['type'] self.type = resp['type']
self.content = resp['body'][resp['type']] return resp['body']
return None
def dump(self):
return self.model_dump_json(indent=2)
class DCPInfo(BaseModel): class DCPInfo(BaseModel):
ID: UUID ID: Optional[UUID] = None
Title: str Title: Optional[str] = None
Path: str Path: Optional[str] = None
Size: int Size: Optional[int] = None
ImportTime: datetime ImportTime: Optional[datetime] = None
IsImported: bool IsImported: Optional[bool] = None
VerifyStatus: bool VerifyStatus: Optional[bool] = None
ValidateStatus: bool ValidateStatus: Optional[bool] = None
IsPlayable: bool IsPlayable: Optional[bool] = None
IsTransferred: bool IsTransferred: Optional[bool] = None
class DCPInfoList(BaseCommand): class DCPInfoList(BaseCommand):
dcpInfoList: List[DCPInfo] path = ['content', 'dcp', 'info', 'list']
path: List[str] = ['content', 'dcp', 'info', 'list'] params = { 'formatDate': 'false' }
params: Dict[str, str] = { 'formatDate': 'false' } dcpInfoList: Optional[List[DCPInfo]] = None
def get(self): def get(self):
self.update(path=self.path, params=self.params) rv = self.update()
self.dcpInfoList = [DCPInfo(**e) for e in self.content] if rv:
self.dcpInfoList = [DCPInfo(**e) for e in rv]
class PowerStatus(BaseModel): class PowerStatus(BaseModel):
Device: str Device: Optional[str] = None
State: str State: Optional[str] = None
class PowerStatusList(BaseCommand): class PowerStatusList(BaseCommand):
powerStatusList: List[PowerStatus] powerStatusList: Optional[List[PowerStatus]] = None
path: List[str] = ['status', 'sms', 'powerstatus'] path = ['status', 'sms', 'powerstatus']
def get(self): def get(self):
self.update(path=self.path) rv = self.update()
self.powerStatusList = [PowerStatus(**e) for e in self.content] if isinstance(rv, dict):
self.powerStatusList = [PowerStatus(**e) for e in rv['PowerStatus']]
class ShowStatusDetailClass(BaseModel): class ShowStatusDetailClass(BaseModel):
Type: str Type: Optional[str] = None
Id: UUID Id: Optional[UUID] = None
RemainingTime: int RemainingTime: Optional[int] = None
ElapsedTime: int ElapsedTime: Optional[int] = None
TotalDuration: int TotalDuration: Optional[int] = None
CurrentEventId: UUID CurrentEventId: Optional[UUID] = None
CurrentEventType: str CurrentEventType: Optional[str] = None
IsStoppedByMalfunction: bool IsStoppedByMalfunction: Optional[bool] = None
RewindTimeList: str RewindTimeList: Optional[str] = None
MalfunctionTime: int MalfunctionTime: Optional[int] = None
class ShowStatus(BaseCommand): class ShowStatus(BaseCommand):
PlayState: str PlayState: Optional[str] = None
ShowStatusDetail: ShowStatusDetailClass ShowStatusDetail: Optional[ShowStatusDetailClass] = None
PlayBackMode: str PlayBackMode: Optional[str] = None
AtmosPlayingStatus: str AtmosPlayingStatus: Optional[str] = None
path: List[str] = ['playback', 'showstatus'] path = ['playback', 'showstatus']
def get(self): def get(self):
self.update(self.path) rv = self.update()
self.PlayState = self.content['PlayState'] if isinstance(rv, dict):
self.ShowStatusDetail = ShowStatusDetailClass(**self.content['StatusDetail']) self.PlayState = rv['PlayState']
self.PlayBackMode = self.content['PlayBackMode'] self.ShowStatusDetail = ShowStatusDetailClass(**rv['ShowStatusDetail'])
self.AtmosPlayingStatus = self.content['AtmosPlayingStatus'] self.PlayBackMode = rv['PlayBackMode']
self.AtmosPlayingStatus = rv['AtmosPlayingStatus']
class ImportProgressClass(BaseModel): class ImportProgressClass(BaseModel):
TotalBytesToTransfer: int TotalBytesToTransfer: Optional[int] = None
BytesTransferred: int BytesTransferred: Optional[int] = None
PercentCompleted: int PercentCompleted: Optional[int] = None
InProgress: int InProgress: Optional[int] = None
ImportPath: str ImportPath: Optional[str] = None
CompletionStatus: str CompletionStatus: Optional[str] = None
CompletionTime: str CompletionTime: Optional[str] = None
DCPTitle: str DCPTitle: Optional[str] = None
class ValidationProgressClass(BaseModel): class ValidationProgressClass(BaseModel):
TotalBytesToValidate: int TotalBytesToValidate: Optional[int] = None
BytesValidated: int BytesValidated: Optional[int] = None
PercentCompleted: int PercentCompleted: Optional[int] = None
InProgress: bool InProgress: Optional[bool] = None
Id: UUID Id: Optional[UUID] = None
CompletionStatus: str CompletionStatus: Optional[str] = None
CompletionTime: datetime CompletionTime: Optional[datetime] = None
class JobProgress(BaseModel): class JobProgress(BaseModel):
Id: int Id: Optional[int] = None
ValidateAfterImport: bool ValidateAfterImport: Optional[bool] = None
AggregatePercentValidated: int AggregatePercentValidated: Optional[int] = None
State: str State: Optional[str] = None
ImportProgress: ImportProgressClass ImportProgress: Optional[ImportProgressClass] = None
ValidationProgressList: List[ValidationProgressClass] ValidationProgressList: Optional[List[ValidationProgressClass]] = None
IngestedByFolder: bool IngestedByFolder: Optional[bool] = None
ContentsTransferType: str ContentsTransferType: Optional[str] = None
class DCPImportJobList(BaseCommand): class DCPImportJobList(BaseCommand):
IsPaused: bool IsPaused: Optional[bool] = None
JobProgressList: List[JobProgress] JobProgressList: Optional[List[JobProgress]] = None
path: List[str] = ['content', 'dcp', 'command'] path = ['content', 'dcp', 'command']
params: Dict[str, str] = {'action': 'ListImportJobs'} params = {'action': 'ListImportJobs'}
def get(self): def get(self):
self.update(self.path) rv = self.update()
self.IsPaused = self.content['IsPaused'] if isinstance(rv, dict):
self.JobProgressList = [JobProgress(**e) for e in self.content['JobProgressList']] self.IsPaused = rv['IsPaused']
self.JobProgressList = [JobProgress(**e) for e in rv['JobProgressList']]

View File

@@ -5,6 +5,7 @@ import logging
import json import json
import projrequest as projrequest import projrequest as projrequest
from commands import ShowStatus, PowerStatusList
from utils import * from utils import *
from influxdb_client_3 import InfluxDBClient3, Point from influxdb_client_3 import InfluxDBClient3, Point
@@ -38,14 +39,16 @@ def main() -> int:
username=env['PROJECTOR_USER'], username=env['PROJECTOR_USER'],
password=env['PROJECTOR_PASSWORD'] password=env['PROJECTOR_PASSWORD']
) )
ps = PowerStatusList(projector=projector)
ss = ShowStatus(projector=projector)
while handler.running: while handler.running:
try: try:
now:float = time.time() now:float = time.time()
resp = projector.get(path=['status', 'storage', 'info'], params={"area":"DCP"}) ps.get()
if resp is not None: ss.get()
print(json.dumps(resp, indent=2)) print(ps.dump())
print(ss.dump())
last: float = time.time() last: float = time.time()
cycle_time: float = last - now cycle_time: float = last - now

View File

@@ -1,4 +1,7 @@
import requests import requests
import urllib3
# Suppress only the single warning from urllib3.
urllib3.disable_warnings(category=urllib3.exceptions.InsecureRequestWarning)
import xmltodict import xmltodict
from requests.auth import HTTPBasicAuth from requests.auth import HTTPBasicAuth
from datetime import datetime from datetime import datetime