Browse Source

sns: read / report handlers with a prepared structure

generalize topic and value representation
breaking change for rpn, since the magnitude *may not* be indexed

also fixes debug logs, where we would always see units of the 1st
magnitude instead of the one being processed
pull/2525/head
Maxim Prokhorov 1 year ago
parent
commit
5fcac5d27f
5 changed files with 59 additions and 55 deletions
  1. +2
    -2
      code/espurna/influxdb.cpp
  2. +5
    -9
      code/espurna/prometheus.cpp
  3. +7
    -9
      code/espurna/rpnrules.cpp
  4. +33
    -28
      code/espurna/sensor.cpp
  5. +12
    -7
      code/espurna/sensor.h

+ 2
- 2
code/espurna/influxdb.cpp View File

@ -158,8 +158,8 @@ void _idbConfigure() {
if (_idb_enabled && !_idb_client) _idbInitClient();
}
void _idbSendSensor(const String& topic, unsigned char id, double, const char* value) {
idbSend(topic.c_str(), id, value);
void _idbSendSensor(const sensor::Value& value) {
idbSend(magnitudeTopic(value.type).c_str(), value.index, value.repr.c_str());
}
void _idbSendStatus(size_t id, bool status) {


+ 5
- 9
code/espurna/prometheus.cpp View File

@ -56,16 +56,12 @@ void handler(AsyncWebServerRequest* request) {
#if SENSOR_SUPPORT
for (unsigned char index = 0; index < magnitudeCount(); ++index) {
auto value = magnitudeValue(index);
if (std::isnan(value.get()) || std::isinf(value.get())) {
continue;
if (value) {
value.topic.remove('/');
response->printf("%s %s\n",
value.topic.c_str(),
value.repr.c_str());
}
String topic(magnitudeTopicIndex(index));
topic.replace("/", "");
response->printf("%s %s\n",
topic.c_str(),
value.toString().c_str());
}
#endif


+ 7
- 9
code/espurna/rpnrules.cpp View File

@ -666,7 +666,7 @@ namespace relay {
void updateVariables(size_t id, bool status) {
char name[32] = {0};
snprintf(name, sizeof(name), "relay%u", id);
snprintf(name, sizeof(name), "relay%zu", id);
rpn_variable_set(internal::context, name, rpn_value(status));
schedule();
@ -1017,16 +1017,14 @@ void init(rpn_context& context) {
#if SENSOR_SUPPORT
namespace sensor {
void updateVariables(const String& topic, unsigned char index, double reading, const char*) {
static_assert(sizeof(double) == sizeof(rpn_float), "");
void updateVariables(const ::sensor::Value& value) {
static_assert(sizeof(decltype(value.value)) == sizeof(rpn_float), "");
String name;
name.reserve(topic.length() + 3);
name += topic;
name += index;
auto topic = value.topic;
topic.remove('/');
rpn_variable_set(internal::context, name, rpn_value(static_cast<rpn_float>(reading)));
rpn_variable_set(internal::context,
topic, rpn_value(static_cast<rpn_float>(value.value)));
}
void init(rpn_context&) {


+ 33
- 28
code/espurna/sensor.cpp View File

@ -3209,21 +3209,33 @@ String _magnitudeTopicIndex(const Magnitude& magnitude) {
return String(buffer);
}
void _sensorReport(unsigned char index, const Magnitude& magnitude) {
sensor::Value _magnitudeValue(const Magnitude& magnitude, double value) {
// XXX: dtostrf only handles basic floating point values and will never produce scientific notation
// ensure decimals is within some sane limit and the actual value never goes above this buffer size
char buffer[64];
dtostrf(magnitude.reported, 1, magnitude.decimals, buffer);
dtostrf(value, 1, magnitude.decimals, buffer);
return sensor::Value {
.type = magnitude.type,
.index = magnitude.index_global,
.units = magnitude.units,
.decimals = magnitude.decimals,
.value = magnitude.reported,
.topic = _magnitudeTopicIndex(magnitude),
.repr = buffer,
};
}
void _sensorReport(unsigned char index, const Magnitude& magnitude) {
const auto value = _magnitudeValue(magnitude, magnitude.reported);
for (auto& handler : _magnitude_report_handlers) {
handler(_magnitudeTopic(magnitude.type), magnitude.index_global, magnitude.reported, buffer);
handler(value);
}
#if MQTT_SUPPORT
{
const String topic(_magnitudeTopicIndex(magnitude));
mqttSend(topic.c_str(), buffer);
mqttSend(value.topic.c_str(), value.repr.c_str());
#if SENSOR_PUBLISH_ADDRESSES
String address_topic;
@ -3243,11 +3255,11 @@ void _sensorReport(unsigned char index, const Magnitude& magnitude) {
// so, we still need to pass / know the 'global' index inside of _magnitudes[]
#if THINGSPEAK_SUPPORT
tspkEnqueueMeasurement(index, buffer);
tspkEnqueueMeasurement(index, value.repr.c_str());
#endif // THINGSPEAK_SUPPORT
#if DOMOTICZ_SUPPORT
domoticzSendMagnitude(magnitude.type, index, magnitude.reported, buffer);
domoticzSendMagnitude(magnitude.type, index, value.value, value.repr.c_str());
#endif // DOMOTICZ_SUPPORT
}
@ -3409,9 +3421,10 @@ void _sensorConfigure() {
#if SENSOR_DEBUG
void _sensorDebugSetup() {
_magnitude_read_handlers.push_front([](const String& topic, unsigned char index, double, const char* repr) {
DEBUG_MSG_P(PSTR("[SENSOR] %s/%hhu -> %s (%s)\n"),
topic.c_str(), index, repr, _magnitudeUnits(_magnitudes[index].units).c_str());
_magnitude_read_handlers.push_front([](const sensor::Value& value) {
DEBUG_MSG_P(PSTR("[SENSOR] %s -> %s%s\n"),
value.topic.c_str(), value.repr.c_str(),
(value.units != sensor::Unit::None) ? _magnitudeUnits(value.units).c_str() : "");
});
}
#endif
@ -3449,28 +3462,21 @@ String magnitudeTopic(unsigned char type) {
return _magnitudeTopic(type);
}
double sensor::Value::get() const {
return real_time ? last : reported;
}
String sensor::Value::toString() const {
char buffer[64] { 0 };
dtostrf(real_time ? last : reported, 1, decimals, buffer);
return buffer;
sensor::Value::operator bool() const {
return !std::isinf(value) && !std::isnan(value);
}
sensor::Value magnitudeValue(unsigned char index) {
sensor::Value result;
sensor::Value out;
out.value = sensor::Value::Unknown;
if (index < _magnitudes.size()) {
const auto& magnitude = _magnitudes[index];
result.real_time = _sensor_real_time;
result.last = magnitude.last;
result.reported = magnitude.reported;
result.decimals = magnitude.decimals;
out = _magnitudeValue(magnitude,
_sensor_real_time ? magnitude.last : magnitude.reported);
}
return result;
return out;
}
unsigned char magnitudeIndex(unsigned char index) {
@ -3695,10 +3701,9 @@ void sensorLoop() {
value.processed = _magnitudeProcess(magnitude, value.raw);
{
char buffer[64];
dtostrf(value.processed, 1, magnitude.decimals, buffer);
const auto out = _magnitudeValue(magnitude, value.processed);
for (auto& handler : _magnitude_read_handlers) {
handler(_magnitudeTopic(magnitude.type), magnitude.index_global, value.processed, buffer);
handler(out);
}
}


+ 12
- 7
code/espurna/sensor.h View File

@ -126,20 +126,25 @@ struct ReadValue {
struct Value {
static constexpr double Unknown { std::numeric_limits<double>::quiet_NaN() };
double get() const;
String toString() const;
unsigned char type;
unsigned char index;
bool real_time { false };
double last { Unknown };
double reported { Unknown };
unsigned char decimals { 0 };
Unit units;
unsigned char decimals;
double value;
String topic;
String repr;
explicit operator bool() const;
};
} // namespace sensor
//--------------------------------------------------------------------------------
using MagnitudeReadHandler = void(*)(const String&, unsigned char, double, const char*);
using MagnitudeReadHandler = void(*)(const sensor::Value&);
void sensorOnMagnitudeRead(MagnitudeReadHandler handler);
void sensorOnMagnitudeReport(MagnitudeReadHandler handler);


Loading…
Cancel
Save