|
|
@ -297,9 +297,9 @@ void forEachError(T&& callback) { |
|
|
|
} |
|
|
|
|
|
|
|
struct ReadValue { |
|
|
|
double raw; |
|
|
|
double processed; |
|
|
|
double filtered; |
|
|
|
double raw; // as the sensor returns it
|
|
|
|
double processed; // after applying units and decimals
|
|
|
|
double filtered; // after applying filters, units and decimals
|
|
|
|
}; |
|
|
|
|
|
|
|
enum class Filter : int { |
|
|
@ -1908,10 +1908,21 @@ Value safe_value_reported(size_t index) { |
|
|
|
|
|
|
|
} // namespace magnitude
|
|
|
|
|
|
|
|
using TimeSource = espurna::time::CoreClock; |
|
|
|
|
|
|
|
enum class State { |
|
|
|
None, |
|
|
|
Initial, |
|
|
|
Idle, |
|
|
|
Resume, |
|
|
|
Ready, |
|
|
|
Reading, |
|
|
|
}; |
|
|
|
|
|
|
|
namespace internal { |
|
|
|
|
|
|
|
std::vector<BaseSensorPtr> sensors; |
|
|
|
bool ready { false }; |
|
|
|
size_t read_count; |
|
|
|
|
|
|
|
bool real_time { build::realTimeValues() }; |
|
|
|
size_t report_every { build::reportEvery() }; |
|
|
@ -3780,8 +3791,38 @@ void setup() { |
|
|
|
// Sensor initialization
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void init() { |
|
|
|
internal::ready = true; |
|
|
|
namespace internal { |
|
|
|
|
|
|
|
State state; |
|
|
|
|
|
|
|
TimeSource::time_point last_init; |
|
|
|
TimeSource::time_point last_reading; |
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
void suspend() { |
|
|
|
for (auto& sensor : internal::sensors) { |
|
|
|
sensor->suspend(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void resume() { |
|
|
|
internal::last_init = TimeSource::now(); |
|
|
|
internal::last_reading = TimeSource::now(); |
|
|
|
internal::read_count = 1; |
|
|
|
|
|
|
|
magnitude::forEachInstance( |
|
|
|
[](sensor::Magnitude& instance) { |
|
|
|
instance.filter->reset(); |
|
|
|
}); |
|
|
|
|
|
|
|
for (auto& sensor : internal::sensors) { |
|
|
|
sensor->resume(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool init() { |
|
|
|
bool out { true }; |
|
|
|
|
|
|
|
for (auto sensor : internal::sensors) { |
|
|
|
// Do not process an already initialized sensor
|
|
|
@ -3800,7 +3841,7 @@ void init() { |
|
|
|
DEBUG_MSG_P(PSTR("[SENSOR] -> ERROR %s (%hhu)\n"), |
|
|
|
sensor::error(error).c_str(), error); |
|
|
|
} |
|
|
|
internal::ready = false; |
|
|
|
out = false; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
@ -3818,43 +3859,73 @@ void init() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (internal::ready) { |
|
|
|
if (out) { |
|
|
|
internal::state = State::Ready; |
|
|
|
DEBUG_MSG_P(PSTR("[SENSOR] Finished initialization for %zu sensor(s) and %zu magnitude(s)\n"), |
|
|
|
sensor::count(), magnitude::count()); |
|
|
|
} |
|
|
|
|
|
|
|
return out; |
|
|
|
} |
|
|
|
|
|
|
|
void loop() { |
|
|
|
// Continiously repeat initialization if there are still some un-initialized sensors after setup()
|
|
|
|
using TimeSource = espurna::time::CoreClock; |
|
|
|
static auto last_init = TimeSource::now(); |
|
|
|
bool try_init() { |
|
|
|
const auto timestamp = TimeSource::now(); |
|
|
|
if (timestamp - internal::last_init > initInterval()) { |
|
|
|
internal::last_init = timestamp; |
|
|
|
return init(); |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
auto timestamp = TimeSource::now(); |
|
|
|
if (!internal::ready && (timestamp - last_init > initInterval())) { |
|
|
|
last_init = timestamp; |
|
|
|
sensor::init(); |
|
|
|
bool ready_to_read() { |
|
|
|
const auto timestamp = TimeSource::now(); |
|
|
|
if (timestamp - internal::last_reading > readInterval()) { |
|
|
|
internal::last_reading = timestamp; |
|
|
|
internal::read_count = (internal::read_count + 1) % reportEvery(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
if (!magnitude::internal::magnitudes.size()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
bool ready_to_report() { |
|
|
|
return internal::read_count == 0; |
|
|
|
} |
|
|
|
|
|
|
|
void loop() { |
|
|
|
// TODO: allow to do nothing
|
|
|
|
if (internal::state == State::Idle) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
static auto last_update = TimeSource::now(); |
|
|
|
static size_t report_count { 0 }; |
|
|
|
// Continiously repeat initialization if there are still some un-initialized sensors after setup()
|
|
|
|
if (internal::state == State::None) { |
|
|
|
internal::state = State::Initial; |
|
|
|
} |
|
|
|
|
|
|
|
sensor::tick(); |
|
|
|
// General initialization, generate magnitudes from available sensors
|
|
|
|
if (internal::state == State::Initial) { |
|
|
|
if (try_init()) { |
|
|
|
internal::state = State::Ready; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (timestamp - last_update > readInterval()) { |
|
|
|
last_update = timestamp; |
|
|
|
report_count = (report_count + 1) % reportEvery(); |
|
|
|
// If magnitudes were initialized and we are ready, prepare to read sensor data
|
|
|
|
if (internal::state == State::Ready) { |
|
|
|
if (magnitude::internal::magnitudes.size() != 0) { |
|
|
|
internal::state = State::Reading; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
sensor::ReadValue value { |
|
|
|
.raw = 0.0, // as the sensor returns it
|
|
|
|
.processed = 0.0, // after applying units and decimals
|
|
|
|
.filtered = 0.0 // after applying filters, units and decimals
|
|
|
|
}; |
|
|
|
if (internal::state != State::Reading) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Tick hook, called every loop()
|
|
|
|
sensor::tick(); |
|
|
|
|
|
|
|
if (ready_to_read()) { |
|
|
|
// Pre-read hook, called every reading
|
|
|
|
sensor::pre(); |
|
|
|
|
|
|
@ -3863,6 +3934,8 @@ void loop() { |
|
|
|
const bool relay_off = (relayCount() == 1) && (relayStatus(0) == 0); |
|
|
|
#endif
|
|
|
|
|
|
|
|
auto value = sensor::ReadValue{}; |
|
|
|
|
|
|
|
for (size_t index = 0; index < magnitude::count(); ++index) { |
|
|
|
auto& magnitude = magnitude::get(index); |
|
|
|
if (!magnitude.sensor->status()) { |
|
|
@ -3913,7 +3986,7 @@ void loop() { |
|
|
|
// -------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Initial status or after report counter overflows
|
|
|
|
bool report { 0 == report_count }; |
|
|
|
bool report { ready_to_report() }; |
|
|
|
|
|
|
|
// In case magnitude was configured with ${name}MaxDelta, override report check
|
|
|
|
// when the value change is greater than the delta
|
|
|
@ -4104,6 +4177,9 @@ void setup() { |
|
|
|
terminal::setup(); |
|
|
|
#endif
|
|
|
|
|
|
|
|
systemBeforeSleep(sensor::suspend); |
|
|
|
systemAfterSleep(sensor::resume); |
|
|
|
|
|
|
|
espurnaRegisterLoop(sensor::loop); |
|
|
|
espurnaRegisterReload(sensor::configure); |
|
|
|
} |
|
|
|