Source code for juham_core.juham_ts

import traceback
from typing import Any, Dict, Optional, cast, Union
from typing_extensions import override
from masterpiece.timeseries import TimeSeries, Measurement
from .juham import Juham


[docs] class JuhamTs(Juham): """Base class for automation objects with timeseries database support. To configure the class to use a specific timeseries database implementation set the `database_class_id` class attribute. When instantiated the object will instantiate the given MQTT object with it. """ database_class_id: str = "" write_attempts: int = 3 def __init__(self, name: str = "") -> None: super().__init__(name) self.database_client: Optional[Union[TimeSeries, None]] = None
[docs] @override def to_dict(self) -> Dict[str, Any]: data: Dict[str, Any] = super().to_dict() if self.database_client is not None: data["_database"] = {"db_client": self.database_client.to_dict()} return data
[docs] @override def from_dict(self, data: Dict[str, Any]) -> None: super().from_dict(data) if "_database" in data: value = data["_database"]["db_client"] self.database_client = cast( Optional[TimeSeries], Juham.instantiate(value["_class"], self.name) ) if self.database_client is not None and "_object" in value: self.database_client.from_dict(value)
[docs] def initialize(self) -> None: self.init_database(self.name) super().initialize()
[docs] def measurement(self, name: str) -> Measurement: timeseries: TimeSeries = cast(TimeSeries, self.database_client) return timeseries.measurement(name)
[docs] def init_database(self, name: str) -> None: if ( JuhamTs.database_class_id != None and Juham.find_class(JuhamTs.database_class_id) != None ): self.database_client = cast( Optional[TimeSeries], Juham.instantiate(JuhamTs.database_class_id) ) else: self.warning("Suspicious configuration: no database_class_id set")
[docs] def write(self, point: Measurement) -> None: if not self.database_client: raise ValueError("Database client is not initialized.") first_exception: Optional[BaseException] = None for i in range(self.write_attempts): try: self.database_client.write(point) return except Exception as e: if first_exception is None: first_exception = e self.warning(f"Writing ts failed, attempt {i+1}: {repr(e)}") self.log_message( "Error", f"Writing failed after {self.write_attempts} attempts, giving up", "".join( traceback.format_exception_only(type(first_exception), first_exception) if first_exception else "No exception" ), )
[docs] def write_point( self, name: str, tags: dict[str, Any], fields: dict[str, Any], ts: str ) -> None: if not self.database_client: raise ValueError("Database client is not initialized.") first_exception: Optional[BaseException] = None for i in range(self.write_attempts): try: self.database_client.write_dict(name, tags, fields, ts) return except Exception as e: if first_exception is None: first_exception is None self.warning(f"Writing ts failed, attempt {i+1}: {repr(e)}") self.log_message( "Error", f"Writing failed after {self.write_attempts} attempts, giving up", "".join( traceback.format_exception_only(type(first_exception), first_exception) ), )
[docs] def read_last_value( self, measurement: str, tags: Optional[dict[str, Any]] = None, fields: Optional[list[str]] = None, ) -> dict[str, Any]: if not self.database_client: raise ValueError("Database client is not initialized.") first_exception: Optional[BaseException] = None for i in range(self.write_attempts): try: return self.database_client.read_last_value(measurement, tags, fields) except Exception as e: if first_exception is None: first_exception = e self.warning(f"Reading ts failed, attempt {i+1}: {repr(e)}") self.log_message( "Error", f"Reading failed after {self.write_attempts} attempts, giving up", "".join( traceback.format_exception_only(type(first_exception), first_exception) ), ) return {}
[docs] def read(self, point: Measurement) -> None: pass