From 29435342b0eedede0841d06bce983057ab10933e Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Tue, 8 Jul 2025 20:41:26 +1000 Subject: [PATCH] * implemented getter methods for telemetry value types --- examples/simple_sensor/SensorMesh.cpp | 119 ++++++++++++++++++++++---- examples/simple_sensor/SensorMesh.h | 14 ++- src/helpers/CommonCLI.cpp | 7 +- src/helpers/CommonCLI.h | 5 +- 4 files changed, 115 insertions(+), 30 deletions(-) diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index 8b1b6f24..293a503c 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -221,10 +221,10 @@ void SensorMesh::applyContactPermissions(const uint8_t* pubkey, uint16_t perms) void SensorMesh::sendAlert(const char* text) { int text_len = strlen(text); - // send text message to all admins + // send text message to all contacts with RECV_ALERT permission for (int i = 0; i < num_contacts; i++) { auto c = &contacts[i]; - if (!c->isAdmin()) continue; + if ((c->permissions & PERM_RECV_ALERTS) == 0) continue; // contact does NOT want alerts uint8_t data[MAX_PACKET_PAYLOAD]; uint32_t now = getRTCClock()->getCurrentTimeUnique(); // need different timestamp per packet @@ -308,7 +308,7 @@ uint8_t SensorMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* MESH_DEBUG_PRINTLN("Login success!"); client->last_timestamp = sender_timestamp; client->last_activity = getRTCClock()->getCurrentTime(); - client->permissions = PERM_IS_ADMIN; + client->permissions = PERM_IS_ADMIN | PERM_RECV_ALERTS; memcpy(client->shared_secret, secret, PUB_KEY_SIZE); dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); @@ -542,7 +542,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise _prefs.cr = LORA_CR; _prefs.tx_power_dbm = LORA_TX_POWER; _prefs.advert_interval = 1; // default to 2 minutes for NEW installs - _prefs.flood_advert_interval = 3; // 3 hours + _prefs.flood_advert_interval = 0; // disabled _prefs.disable_fwd = true; _prefs.flood_max = 64; _prefs.interference_threshold = 0; // disabled @@ -604,6 +604,102 @@ void SensorMesh::setTxPower(uint8_t power_dbm) { radio_set_tx_power(power_dbm); } +static uint8_t getDataSize(uint8_t type) { + switch (type) { + case LPP_GPS: + return 9; + case LPP_POLYLINE: + return 8; // TODO: this is MINIMIUM + case LPP_GYROMETER: + case LPP_ACCELEROMETER: + return 6; + case LPP_GENERIC_SENSOR: + case LPP_FREQUENCY: + case LPP_DISTANCE: + case LPP_ENERGY: + case LPP_UNIXTIME: + return 4; + case LPP_COLOUR: + return 3; + case LPP_ANALOG_INPUT: + case LPP_ANALOG_OUTPUT: + case LPP_LUMINOSITY: + case LPP_TEMPERATURE: + case LPP_CONCENTRATION: + case LPP_BAROMETRIC_PRESSURE: + case LPP_ALTITUDE: + case LPP_VOLTAGE: + case LPP_CURRENT: + case LPP_DIRECTION: + case LPP_POWER: + return 2; + } + return 1; +} + +static uint32_t getMultiplier(uint8_t type) { + switch (type) { + case LPP_CURRENT: + case LPP_DISTANCE: + case LPP_ENERGY: + return 1000; + case LPP_VOLTAGE: + case LPP_ANALOG_INPUT: + case LPP_ANALOG_OUTPUT: + return 100; + case LPP_TEMPERATURE: + case LPP_BAROMETRIC_PRESSURE: + return 10; + } + return 1; +} + +static bool isSigned(uint8_t type) { + return type == LPP_ALTITUDE || type == LPP_TEMPERATURE || type == LPP_GYROMETER || + type == LPP_ANALOG_INPUT || type == LPP_ANALOG_OUTPUT || type == LPP_GPS || type == LPP_ACCELEROMETER; +} + +static float getFloat(const uint8_t * buffer, uint8_t size, uint32_t multiplier, bool is_signed) { + uint32_t value = 0; + for (uint8_t i = 0; i < size; i++) { + value = (value << 8) + buffer[i]; + } + + int sign = 1; + if (is_signed) { + uint32_t bit = 1ul << ((size * 8) - 1); + if ((value & bit) == bit) { + value = (bit << 1) - value; + sign = -1; + } + } + return sign * ((float) value / multiplier); +} + +float SensorMesh::getTelemValue(uint8_t channel, uint8_t type) { + auto buf = telemetry.getBuffer(); + uint8_t size = telemetry.getSize(); + uint8_t i = 0; + + while (i + 2 < size) { + // Get channel # + uint8_t ch = buf[i++]; + // Get data type + uint8_t t = buf[i++]; + uint8_t sz = getDataSize(t); + + if (ch == channel && t == type) { + return getFloat(&buf[i], sz, getMultiplier(t), isSigned(t)); + } + i += sz; // skip + } + return 0.0f; // not found +} + +bool SensorMesh::getGPS(uint8_t channel, float& lat, float& lon, float& alt) { + return false; // TODO +} + void SensorMesh::loop() { mesh::Mesh::loop(); @@ -629,21 +725,6 @@ void SensorMesh::loop() { onSensorDataRead(); - // save telemetry to time-series datastore - File file = openAppend(_fs, "/s_data"); - if (file) { - file.write((uint8_t *)&curr, 4); // start record with RTC timestamp - uint8_t tlen = telemetry.getSize(); - file.write(&tlen, 1); - file.write(telemetry.getBuffer(), tlen); - uint8_t zero = 0; - while (tlen < MAX_PACKET_PAYLOAD - 4) { // pad with zeroes, for fixed record length - file.write(&zero, 1); - tlen++; - } - file.close(); - } - last_read_time = curr; } diff --git a/examples/simple_sensor/SensorMesh.h b/examples/simple_sensor/SensorMesh.h index 196acb8f..05104c99 100644 --- a/examples/simple_sensor/SensorMesh.h +++ b/examples/simple_sensor/SensorMesh.h @@ -26,6 +26,7 @@ #define PERM_IS_ADMIN 0x8000 #define PERM_GET_TELEMETRY 0x0001 #define PERM_GET_MIN_MAX_AVG 0x0002 +#define PERM_RECV_ALERTS 0x0100 struct ContactInfo { mesh::Identity id; @@ -83,9 +84,18 @@ public: const uint8_t* getSelfIdPubKey() override { return self_id.pub_key; } void clearStats() override { } + float getTelemValue(uint8_t channel, uint8_t type); + protected: - // telemetry data queries - float getVoltage(uint8_t channel) { return 0.0f; } // TODO: extract from curr telemetry buffer + // current telemetry data queries + float getVoltage(uint8_t channel) { return getTelemValue(channel, LPP_VOLTAGE); } + float getCurrent(uint8_t channel) { return getTelemValue(channel, LPP_CURRENT); } + float getPower(uint8_t channel) { return getTelemValue(channel, LPP_POWER); } + float getTemperature(uint8_t channel) { return getTelemValue(channel, LPP_TEMPERATURE); } + float getRelativeHumidity(uint8_t channel) { return getTelemValue(channel, LPP_RELATIVE_HUMIDITY); } + float getBarometricPressure(uint8_t channel) { return getTelemValue(channel, LPP_BAROMETRIC_PRESSURE); } + float getAltitude(uint8_t channel) { return getTelemValue(channel, LPP_ALTITUDE); } + bool getGPS(uint8_t channel, float& lat, float& lon, float& alt); // alerts struct Trigger { diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 97b4ffe1..df510c28 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -120,10 +120,11 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { #define MIN_LOCAL_ADVERT_INTERVAL 60 -void CommonCLI::checkAdvertInterval() { +void CommonCLI::savePrefs() { if (_prefs->advert_interval * 2 < MIN_LOCAL_ADVERT_INTERVAL) { _prefs->advert_interval = 0; // turn it off, now that device has been manually configured } + _callbacks->savePrefs(); } void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, char* reply) { @@ -166,7 +167,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } else if (memcmp(command, "password ", 9) == 0) { // change admin password StrHelper::strncpy(_prefs->password, &command[9], sizeof(_prefs->password)); - checkAdvertInterval(); savePrefs(); sprintf(reply, "password now: %s", _prefs->password); // echo back just to let admin know for sure!! } else if (memcmp(command, "clear stats", 11) == 0) { @@ -265,7 +265,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch strcpy(reply, "OK"); } else if (memcmp(config, "name ", 5) == 0) { StrHelper::strncpy(_prefs->node_name, &config[5], sizeof(_prefs->node_name)); - checkAdvertInterval(); savePrefs(); strcpy(reply, "OK"); } else if (memcmp(config, "repeat ", 7) == 0) { @@ -292,12 +291,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } } else if (memcmp(config, "lat ", 4) == 0) { _prefs->node_lat = atof(&config[4]); - checkAdvertInterval(); savePrefs(); strcpy(reply, "OK"); } else if (memcmp(config, "lon ", 4) == 0) { _prefs->node_lon = atof(&config[4]); - checkAdvertInterval(); savePrefs(); strcpy(reply, "OK"); } else if (memcmp(config, "rxdelay ", 8) == 0) { diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 1778c715..b50bf7f3 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -55,10 +55,7 @@ class CommonCLI { char tmp[80]; mesh::RTCClock* getRTCClock() { return _rtc; } - void savePrefs() { _callbacks->savePrefs(); } - - void checkAdvertInterval(); - + void savePrefs(); void loadPrefsInt(FILESYSTEM* _fs, const char* filename); public: