Skip to content

Commit

Permalink
sns: read / report handlers with a prepared structure
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mcspr committed May 21, 2022
1 parent 683347c commit 5fcac5d
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 55 deletions.
4 changes: 2 additions & 2 deletions code/espurna/influxdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
14 changes: 5 additions & 9 deletions code/espurna/prometheus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
16 changes: 7 additions & 9 deletions code/espurna/rpnrules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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&) {
Expand Down
61 changes: 33 additions & 28 deletions code/espurna/sensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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

}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
}

Expand Down
19 changes: 12 additions & 7 deletions code/espurna/sensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 5fcac5d

Please sign in to comment.