1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- from flask import abort
- from marshmallow import fields, ValidationError
- from sqlalchemy import select
- from flexmeasures.data import db
- from flexmeasures.api import FMValidationError
- from flexmeasures.utils.entity_address_utils import (
- parse_entity_address,
- EntityAddressException,
- )
- from flexmeasures.data.models.time_series import Sensor
- from flexmeasures.utils.unit_utils import is_valid_unit
- class EntityAddressValidationError(FMValidationError):
- status = "INVALID_DOMAIN" # USEF error status
- class SensorIdField(fields.Integer):
- """
- Field that represents a sensor ID. It de-serializes from the sensor id to a sensor instance.
- """
- def _deserialize(self, sensor_id: int, attr, obj, **kwargs) -> Sensor:
- sensor: Sensor = db.session.execute(
- select(Sensor).filter_by(id=int(sensor_id))
- ).scalar_one_or_none()
- if sensor is None:
- raise abort(404, f"Sensor {sensor_id} not found")
- return sensor
- def _serialize(self, sensor: Sensor, attr, data, **kwargs) -> int:
- return sensor.id
- class SensorField(fields.Str):
- """Field that de-serializes to a Sensor,
- and serializes a Sensor into an entity address (string).
- """
- # todo: when Actuators also get an entity address, refactor this class to EntityField,
- # where an Entity represents anything with an entity address: we currently foresee Sensors and Actuators
- def __init__(
- self,
- entity_type: str = "sensor",
- fm_scheme: str = "fm1",
- *args,
- **kwargs,
- ):
- """
- :param entity_type: "sensor" (in the future, possibly also another type of resource that is assigned an entity address)
- :param fm_scheme: "fm0" or "fm1"
- """
- self.entity_type = entity_type
- self.fm_scheme = fm_scheme
- super().__init__(*args, **kwargs)
- def _deserialize(self, value, attr, obj, **kwargs) -> Sensor:
- """De-serialize to a Sensor."""
- try:
- ea = parse_entity_address(value, self.entity_type, self.fm_scheme)
- if self.fm_scheme == "fm0":
- raise EntityAddressException("The fm0 scheme is no longer supported.")
- else:
- sensor = db.session.execute(
- select(Sensor).filter_by(id=ea["sensor_id"])
- ).scalar_one_or_none()
- if sensor is not None:
- return sensor
- else:
- raise EntityAddressValidationError(
- f"{self.entity_type} with entity address {value} doesn't exist."
- )
- except EntityAddressException as eae:
- raise EntityAddressValidationError(str(eae))
- def _serialize(self, value: Sensor, attr, data, **kwargs):
- """Serialize to an entity address."""
- if self.fm_scheme == "fm0":
- return value.entity_address_fm0
- else:
- return value.entity_address
- class UnitField(fields.Str):
- """Field that represents a unit."""
- def _deserialize(self, value, attr, data, **kwargs) -> str:
- if not is_valid_unit(value):
- raise ValidationError(f"Invalid unit: {value}")
- return value
- def _serialize(self, value: str, attr, obj, **kwargs) -> str:
- return value
|