/* SENSOR MODULE Copyright (C) 2016-2019 by Xose PĂ©rez Copyright (C) 2020 by Maxim Prokhorov */ #pragma once #include #include #include #include namespace sensor { enum class Unit : int { Min_, None, Celcius, Farenheit, Kelvin, Percentage, Hectopascal, Ampere, Volt, Voltampere, Kilovoltampere, VoltampereReactive, KilovoltampereReactive, Watt, Kilowatt, WattSecond, Joule = WattSecond, KilowattHour, PartsPerMillion, Ohm, MicrogrammPerCubicMeter, // The concentration of an air pollutant MilligrammPerCubicMeter, // Lux, UltravioletIndex, // "measurement of the strength of sunburn-producing ultraviolet (UV) radiation at a particular place and time" // (XXX: Not a unit. Distinguish from None and specify decimals) CountsPerMinute, // Unit of local dose rate (Geiger counting) MicrosievertPerHour, // 2nd unit of local dose rate (Geiger counting) Meter, Hertz, Ph }; // Base units are 32 bit since we are the fastest with them. struct Ws { Ws(); Ws(uint32_t); uint32_t value; }; struct Wh { Wh(); Wh(Ws); Wh(uint32_t); uint32_t value; }; struct KWh { KWh(); KWh(Ws); KWh(Wh); KWh(uint32_t); uint32_t value; }; struct Energy { constexpr static uint32_t KwhMultiplier = 3600000ul; constexpr static uint32_t KwhLimit = ((1ul << 31ul) / KwhMultiplier); Energy() = default; // TODO: while we accept ws >= the kwh conversion limit, // should this be dealt with on the unit level? explicit Energy(double); explicit Energy(KWh, Ws); explicit Energy(KWh); explicit Energy(Wh); explicit Energy(Ws); // Sets internal counters to zero void reset(); // Check whether we have *any* energy recorded. Can be zero: // - on cold boot // - on overflow // - when we call `reset()` explicit operator bool() const; // Generic conversion as-is double asDouble() const; String asString() const; // Convert back to input unit, with overflow mechanics when kwh values goes over 32 bit Ws asWs() const; // Generic sensors output energy in joules / watt-second Energy& operator +=(Ws); Energy operator +(Ws); // But sometimes we want to accept asDouble() value back Energy& operator =(double); // We are storing a kind-of integral and fractional parts // Using watt-second to avoid loosing precision, we don't expect these to be accessed directly KWh kwh; Ws ws; }; struct ReadValue { double raw; double processed; double filtered; }; struct Value { static constexpr double Unknown { std::numeric_limits::quiet_NaN() }; unsigned char type; unsigned char index; Unit units; unsigned char decimals; double value; String topic; String repr; explicit operator bool() const; }; } // namespace sensor //-------------------------------------------------------------------------------- using MagnitudeReadHandler = void(*)(const sensor::Value&); void sensorOnMagnitudeRead(MagnitudeReadHandler handler); void sensorOnMagnitudeReport(MagnitudeReadHandler handler); String magnitudeUnits(unsigned char index); String magnitudeDescription(unsigned char index); unsigned char magnitudeType(unsigned char index); unsigned char magnitudeIndex(unsigned char index); String magnitudeTopicIndex(unsigned char index); unsigned char magnitudeCount(); sensor::Value magnitudeValue(unsigned char index); // XXX: without param name it is kind of vague what exactly unsigned char is // consider adding stronger param type e.g. enum class String magnitudeTopic(unsigned char type); String magnitudeName(unsigned char type); String sensorError(unsigned char error); using SensorWebSocketMagnitudesCallback = void(*)(JsonArray&, size_t); void sensorWebSocketMagnitudes(JsonObject& root, const char* prefix, SensorWebSocketMagnitudesCallback); unsigned char sensorCount(); void sensorSetup(); void sensorLoop();