Example #1
0
class ObsData(base.ObsData):
    """SDS01x observations

    time                                    measurement time [seconds since epoch]
    raw25, raw10                            PM2.5*10, PM10*10 [ug/m3]
    """

    pm25: float = field(
        metadata=base.metadata("PM2.5", "ug/m3", "concentration"))
    pm10: float = field(
        metadata=base.metadata("PM10", "ug/m3", "concentration"))

    def __post_init__(self):
        """Convert from 0.1 ug/m3 to ug/m3"""
        self.pm25 /= 10
        self.pm10 /= 10

    def __format__(self, spec: str) -> str:
        if spec == "header":
            return super().__format__(spec)
        if spec == "pm":
            return f"{self.date:%F %T}: PM2.5 {self.pm25:.1f}, PM10 {self.pm10:.1f} ug/m3"
        if spec == "csv":
            return f"{self.time}, {self.pm25:.1f}, {self.pm10:.1f}"
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")
Example #2
0
class ObsData(base.ObsData):
    """Observations from Honeywell HPMA115C0 sensors

    time                                    measurement time [seconds since epoch]
    pm01, pm25, pm04, pm10                  PM1.0, PM2.5, PM4.0 PM10 [ug/m3]
    """

    pm01: int = field(metadata=base.metadata("PM1", "ug/m3", "concentration"))
    pm25: int = field(
        metadata=base.metadata("PM2.5", "ug/m3", "concentration"))
    pm04: int = field(metadata=base.metadata("PM4", "ug/m3", "concentration"))
    pm10: int = field(metadata=base.metadata("PM10", "ug/m3", "concentration"))

    def __format__(self, spec: str) -> str:
        if spec == "header":
            return super().__format__(spec)
        if spec == "pm":
            return f"{self.date:%F %T}: PM1 {self.pm01:.1f}, PM2.5 {self.pm25:.1f}, PM4 {self.pm04:.1f}, PM10 {self.pm10:.1f} ug/m3"
        if spec == "csv":
            return (
                f"{self.time}, {self.pm01:.1f}, {self.pm25:.1f}, {self.pm04:.1f}, {self.pm10:.1f}"
            )
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")
Example #3
0
class ObsData(base.ObsData):
    """Observations from Plantower PMS3003 sensors

    time                                    measurement time [seconds since epoch]
    raw01, raw25, raw10                     cf=1 PM estimates [ug/m3]
    pm01, pm25, pm10                        PM1.0, PM2.5, PM10 [ug/m3]
    """

    raw01: int = field(repr=False)
    raw25: int = field(repr=False)
    raw10: int = field(repr=False)
    pm01: int = field(metadata=base.metadata("PM1", "ug/m3", "concentration"))
    pm25: int = field(
        metadata=base.metadata("PM2.5", "ug/m3", "concentration"))
    pm10: int = field(metadata=base.metadata("PM10", "ug/m3", "concentration"))

    # cfX [1]: pmX/rawX
    @property
    def cf01(self) -> float:
        return self._safe_div(self.pm01, self.raw01)

    @property
    def cf25(self) -> float:
        return self._safe_div(self.pm25, self.raw25)

    @property
    def cf10(self) -> float:
        return self._safe_div(self.pm10, self.raw10)

    @staticmethod
    def _safe_div(x: int, y: int) -> float:
        if y:
            return x / y
        if x == y == 0:  # pragma: no cover
            return 1
        return 0  # pragma: no cover

    def __format__(self, spec: str) -> str:
        if spec == "header":
            return super().__format__(spec)
        if spec == "pm":
            return f"{self.date:%F %T}: PM1 {self.pm01:.1f}, PM2.5 {self.pm25:.1f}, PM10 {self.pm10:.1f} ug/m3"
        if spec == "csv":
            return f"{self.time}, {self.raw01}, {self.raw25}, {self.raw10}, {self.pm01:.1f}, {self.pm25:.1f}, {self.pm10:.1f}"
        if spec == "cf":
            return f"{self.date:%F %T}: CF1 {self.cf01:.0%}, CF2.5 {self.cf25:.0%}, CF10 {self.cf10:.0%}"
        if spec == "raw":
            return (
                f"{self.date:%F %T}: PM1 {self.raw01}, PM2.5 {self.raw25}, PM10 {self.raw10} ug/m3"
            )
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")
Example #4
0
class ObsData(pms3003.ObsData):
    """Observations from Plantower PMS5003T sensors

    time                                    measurement time [seconds since epoch]
    raw01, raw25, raw10                     cf=1 PM estimates [ug/m3]
    pm01, pm25, pm10                        PM1.0, PM2.5, PM10 [ug/m3]
    n0_3, n0_5, n1_0, n2_5                  number concentrations over X.Y um [#/cm3]
    temp                                    temperature [°C]
    rhum                                    relative humidity [%]
    """

    # nX_Y [#/cm3]: number concentrations over X.Y um (read as 100*nX_Y)
    n0_3: float
    n0_5: float
    n1_0: float
    n2_5: float
    # temp[°C],rhum[%]: temperature,relative humidity (read as 10*temp,10*rhum)
    temp: float = field(metadata=base.metadata("temperature", "°C", "degrees"))
    rhum: float = field(
        metadata=base.metadata("relative humidity", "%", "percentage"))

    def __post_init__(self):
        """Units conversion
        nX_Y [#/cm3] read in [#/0.1L]
        temp [°C]    read in [0.1 °C]
        rhum [%]     read in [1/1000]
        """
        self.n0_3 /= 100
        self.n0_5 /= 100
        self.n1_0 /= 100
        self.n2_5 /= 100
        self.temp /= 10
        self.rhum /= 10

        if self.n0_3 == 0 and self.pm10 > 0:
            raise InconsistentObservation(
                f"inconsistent obs: PM10={self.pm10} and N0.3={self.n0_3}")

    def __format__(self, spec: str) -> str:
        if spec in ["header", "pm", "raw", "cf"]:
            return super().__format__(spec)
        if spec == "csv":
            pm = super().__format__(spec)
            return f"{pm}, {self.n0_3:.2f}, {self.n0_5:.2f}, {self.n1_0:.2f}, {self.n2_5:.2f}, {self.temp:.1f}, {self.rhum:.1f}"
        if spec == "num":
            return f"{self.date:%F %T}: N0.3 {self.n0_3:.2f}, N0.5 {self.n0_5:.2f}, N1.0 {self.n1_0:.2f}, N2.5 {self.n2_5:.2f} #/cm3"
        if spec == "atm":
            return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %"
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")
Example #5
0
class ObsData(pmsx003.ObsData):
    """Observations from Plantower PMS5003S sensors

    time                                    measurement time [seconds since epoch]
    raw01, raw25, raw10                     cf=1 PM estimates [ug/m3]
    pm01, pm25, pm10                        PM1.0, PM2.5, PM10 [ug/m3]
    n0_3, n0_5, n1_0, n2_5, n5_0, n10_0     number concentrations over X.Y um [#/cm3]
    HCHO                                    formaldehyde concentration [mg/m3]
    """

    # HCHO [mg/m3]: formaldehyde concentration (read as ug/m3, datasheet says 1/1000 mg/m3 ie ug/m3)
    HCHO: int = field(
        metadata=base.metadata("formaldehyde", "mg/m3", "concentration"))

    def __post_init__(self):
        """Units conversion
        nX_Y [#/cm3] read in [#/0.1L]
        HCHO [mg/m3] read in [ug/m3]
        """
        super().__post_init__()
        self.HCHO /= 1000

    def __format__(self, spec: str) -> str:
        if spec in ["header", "pm", "raw", "cf", "num"]:
            return super().__format__(spec)
        if spec == "csv":
            csv = super().__format__(spec)
            return f"{csv}, {self.HCHO:.3f}"
        if spec == "hcho":
            return f"{self.date:%F %T}: HCHO {self.HCHO:.3f} mg/m3"
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")
Example #6
0
class ObsData(base.ObsData):
    """SPS30 observations

    time                                    measurement time [seconds since epoch]
    pm01, pm25, pm04, pm10                  PM1.0, PM2.5, PM4.0, PM10 [ug/m3]
    n0_5, n1_0, n2_5, n4_0, n10_0           number concentrations between 0.3 and X.Y um [#/cm3]
    diam                                    typical particle size [μm]
    """

    pm01: float = field(
        metadata=base.metadata("PM1", "ug/m3", "concentration"))
    pm25: float = field(
        metadata=base.metadata("PM2.5", "ug/m3", "concentration"))
    pm04: float = field(
        metadata=base.metadata("PM4", "ug/m3", "concentration"))
    pm10: float = field(
        metadata=base.metadata("PM10", "ug/m3", "concentration"))
    n0_5: float
    n1_0: float
    n2_5: float
    n4_0: float
    n10_0: float
    diam: float

    def __format__(self, spec: str) -> str:
        if spec == "header":
            return super().__format__(spec)
        if spec == "pm":
            return f"{self.date:%F %T}: PM1 {self.pm01:.1f}, PM2.5 {self.pm25:.1f}, PM4 {self.pm04:.1f}, PM10 {self.pm10:.1f} ug/m3"
        if spec == "csv":
            pm = f"{self.pm01:.1f}, {self.pm25:.1f}, {self.pm04:.1f}, {self.pm10:.1f}"
            num = f"{self.n0_5:.2f}, {self.n1_0:.2f}, {self.n2_5:.2f}, {self.n4_0:.2f}, {self.n10_0:.2f}"
            return f"{self.time}, {pm}, {num}, {self.diam:.1f}"
        if spec == "num":
            return f"{self.date:%F %T}: N0.5 {self.n0_5:.2f}, N1.0 {self.n1_0:.2f}, N2.5 {self.n2_5:.2f}, N4.0 {self.n4_0:.2f}, N10 {self.n10_0:.2f} #/cm3"
        if spec == "diam":
            return f"{self.date:%F %T}: Ø {self.diam:.1f} μm"
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")
Example #7
0
class ObsData(pms5003s.ObsData):
    """Observations from Plantower PMS5003ST sensors

    time                                    measurement time [seconds since epoch]
    raw01, raw25, raw10                     cf=1 PM estimates [ug/m3]
    pm01, pm25, pm10                        PM1.0, PM2.5, PM10 [ug/m3]
    n0_3, n0_5, n1_0, n2_5, n5_0, n10_0     number concentrations over X.Y um [#/cm3]
    HCHO                                    formaldehyde concentration [mg/m3]
    temp                                    temperature [°C]
    rhum                                    relative humidity [%]
    """

    # temp[°C],rhum[%]: temperature,relative humidity (read as 10*temp,10*rhum)
    temp: float = field(metadata=base.metadata("temperature", "°C", "degrees"))
    rhum: float = field(metadata=base.metadata("relative humidity", "%", "percentage"))

    def __post_init__(self):
        """Units conversion
        nX_Y [#/cm3] read in [#/0.1L]
        HCHO [mg/m3] read in [ug/m3]
        temp [°C]    read in [0.1 °C]
        rhum [%]     read in [1/1000]
        """
        super().__post_init__()
        self.temp /= 10
        self.rhum /= 10

    def __format__(self, spec: str) -> str:
        if spec in ["header", "pm", "raw", "cf", "num", "hcho"]:
            return super().__format__(spec)
        if spec == "csv":
            csv = super().__format__(spec)
            return f"{csv}, {self.temp:.1f}, {self.rhum:.1f}"
        if spec == "atm":
            return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %"
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'"
        )
Example #8
0
class ObsData(base.ObsData):
    """SDS198 observations

    time                                    measurement time [seconds since epoch]
    pm100                                   PM100 [ug/m3]
    """

    pm100: int = field(
        metadata=base.metadata("PM100", "ug/m3", "concentration"))

    def __format__(self, spec: str) -> str:
        if spec == "header":
            return super().__format__(spec)
        if spec == "pm":
            return f"{self.date:%F %T}: PM100 {self.pm100:.1f} ug/m3"
        if spec == "csv":
            return f"{self.time}, {self.pm100:.1f}"
        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")
Example #9
0
class ObsData(base.ObsData):
    """Observations from Plantower PMS3003 sensors

    time                                    measurement time [seconds since epoch]
    temp                                    temperature [°C]
    rhum                                    relative humidity [%]
    press                                   atmospheric pressure [hPa]
    IAQ_acc                                 IAQ accuracy flag
    IAQ                                     index of air quality [0--500]
    gas                                     gas resistance [kΩ]
    alt                                     altitude estimate [m a.s.l.]
    """

    # temp[°C],rhum[%]: temperature,relative humidity (read as 100*temp,100*rhum)
    temp: float = field(metadata=base.metadata("temperature", "°C", "degrees"))
    rhum: float = field(
        metadata=base.metadata("relative humidity", "%", "percentage"))
    # press[hPa]: atm. pressure (read as 24b in hPa)
    # on read press XSB(8b)|MSB(8b)
    pres: float = field(
        metadata=base.metadata("atmospheric pressure", "hPa", "pressure"))
    # on read press LSB(8b)
    IAQ_acc: int = field(metadata=base.metadata("IAQ acc", "1", "acc"))
    # on read IAQ_acc(4b)|IAQ(12b) packed into 16b
    IAQ: int = field(metadata=base.metadata("IAQ", "0-500", "iaq"))
    gas: int = field(
        metadata=base.metadata("gas resistance", "kΩ", "resistance"))
    alt: int = field(
        metadata=base.metadata("altitude estimate", "m(a.s.l.)", "elevation"))

    def __post_init__(self):
        """Units conversion
        temp [°C]    read in [0.01 °C]
        rhum [%]     read in [1/10 000]
        press [hPa]  read in [Pa] across 12b
        gas [kΩ]   read in [Ω]
        """
        self.temp /= 100
        self.rhum /= 100
        self.press = (int(self.pres) << 8 | self.IAQ_acc) / 100
        self.IAQ_acc = self.IAQ >> 4
        self.IAQ &= 0x0FFF
        self.gas /= 1000

    def __format__(self, spec: str) -> str:
        if spec == "header":
            return super().__format__(spec)
        if spec == "atm":
            return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %, Press {self.press:.2f} hPa"
        if spec == "bme":
            return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %, Press {self.press:.2f} hPa, {self.gas:.1f} kΩ"
        if spec == "bsec":
            return f"{self.date:%F %T}: Temp. {self.temp:.1f} °C, Rel.Hum. {self.rhum:.1f} %, Press {self.press:.2f} hPa, {self.IAQ} IAQ"
        if spec == "csv":
            return f"{self.time}, {self.temp:.1f}, {self.rhum:.1f}, {self.press:.2f}, {self.IAQ_acc}, {self.IAQ}, {self.gas:.1f}, {self.alt}"

        raise ValueError(  # pragma: no cover
            f"Unknown format code '{spec}' "
            f"for object of type '{__name__}.{self.__class__.__name__}'")

    def __str__(self):
        return self.__format__("bme")