From 40f470ebf2e2147e9cd484e1aff2eb42e4c05aeb Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Mon, 11 May 2026 21:33:49 +0200 Subject: [PATCH] Sensors page: show placeholders for all connected sensors; support all LPP types - SensorManager::getAvailableLPPTypes() reports which LPP types will be present based on initialized sensor flags (temp, humidity, pressure, etc.) - Sensors page renders one row per available type; shows "--" for any sensor that hasn't produced a reading yet instead of hiding the row entirely - LPPReader: add readLuminosity, readPercentage, readConcentration, readDistance - All known LPP types now have proper names and units in the sensor display Co-Authored-By: Claude Sonnet 4.6 --- examples/companion_radio/ui-new/UITask.cpp | 117 +++++++++--------- src/helpers/SensorManager.h | 1 + .../sensors/EnvironmentSensorManager.cpp | 40 ++++++ .../sensors/EnvironmentSensorManager.h | 1 + src/helpers/sensors/LPPDataHelpers.h | 16 +++ 5 files changed, 117 insertions(+), 58 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index e4ee3b02..ac6dc39a 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -1976,72 +1976,73 @@ public: } else if (_page == HomePage::SENSORS) { int y = 18; refresh_sensors(); - char buf[30]; - char name[30]; - LPPReader r(sensors_lpp.getBuffer(), sensors_lpp.getSize()); - for (int i = 0; i < sensors_scroll_offset; i++) { - uint8_t channel, type; - r.readHeader(channel, type); - r.skipData(type); - } + uint8_t avail_types[16]; + int avail_count = _sensors ? _sensors->getAvailableLPPTypes(avail_types, 16) : 0; + bool need_scroll = avail_count > UI_RECENT_LIST_SIZE; + int offset = need_scroll ? (sensors_scroll_offset % avail_count) : 0; + int show_n = need_scroll ? UI_RECENT_LIST_SIZE : avail_count; - for (int i = 0; i < (sensors_scroll?UI_RECENT_LIST_SIZE:sensors_nb); i++) { - uint8_t channel, type; - if (!r.readHeader(channel, type)) { // reached end, reset - r.reset(); - r.readHeader(channel, type); + for (int i = 0; i < show_n; i++) { + uint8_t target = avail_types[(offset + i) % avail_count]; + + // scan LPP buffer for this type + LPPReader r(sensors_lpp.getBuffer(), sensors_lpp.getSize()); + uint8_t ch, type; + bool found = false; + char buf[22] = "--"; + while (r.readHeader(ch, type)) { + if (type == target) { + float v, v2, v3; + switch (type) { + case LPP_GPS: + r.readGPS(v, v2, v3); + if (v != 0 || v2 != 0) snprintf(buf, sizeof(buf), "%.4f %.4f", v, v2); + break; + case LPP_VOLTAGE: r.readVoltage(v); snprintf(buf, sizeof(buf), "%.2fV", v); break; + case LPP_CURRENT: r.readCurrent(v); snprintf(buf, sizeof(buf), "%.3fA", v); break; + case LPP_POWER: r.readPower(v); snprintf(buf, sizeof(buf), "%.1fW", v); break; + case LPP_TEMPERATURE:r.readTemperature(v); snprintf(buf, sizeof(buf), "%.1f\xf8""C", v); break; + case LPP_RELATIVE_HUMIDITY: r.readRelativeHumidity(v); snprintf(buf, sizeof(buf), "%.0f%%", v); break; + case LPP_BAROMETRIC_PRESSURE: r.readPressure(v); snprintf(buf, sizeof(buf), "%.1fhPa", v); break; + case LPP_ALTITUDE: r.readAltitude(v); snprintf(buf, sizeof(buf), "%.0fm", v); break; + case LPP_LUMINOSITY: r.readLuminosity(v); snprintf(buf, sizeof(buf), "%.0flux", v); break; + case LPP_PERCENTAGE: r.readPercentage(v); snprintf(buf, sizeof(buf), "%.0f%%", v); break; + case LPP_DISTANCE: r.readDistance(v); snprintf(buf, sizeof(buf), "%.2fm", v); break; + case LPP_CONCENTRATION: r.readConcentration(v); snprintf(buf, sizeof(buf), "%.0fppm", v); break; + default: r.skipData(type); continue; + } + found = true; + break; + } + r.skipData(type); } + (void)found; + + static const struct { uint8_t type; const char* name; } TYPE_NAMES[] = { + { LPP_VOLTAGE, "voltage" }, + { LPP_GPS, "gps" }, + { LPP_TEMPERATURE, "temp" }, + { LPP_RELATIVE_HUMIDITY, "humidity" }, + { LPP_BAROMETRIC_PRESSURE,"pressure" }, + { LPP_ALTITUDE, "altitude" }, + { LPP_CURRENT, "current" }, + { LPP_POWER, "power" }, + { LPP_LUMINOSITY, "light" }, + { LPP_PERCENTAGE, "moisture" }, + { LPP_DISTANCE, "distance" }, + { LPP_CONCENTRATION, "CO2" }, + }; + const char* name = "sensor"; + for (auto& tn : TYPE_NAMES) { if (tn.type == target) { name = tn.name; break; } } - display.setCursor(0, y); - float v; - switch (type) { - case LPP_GPS: // GPS - float lat, lon, alt; - r.readGPS(lat, lon, alt); - strcpy(name, "gps"); sprintf(buf, "%.4f %.4f", lat, lon); - break; - case LPP_VOLTAGE: - r.readVoltage(v); - strcpy(name, "voltage"); sprintf(buf, "%6.2f", v); - break; - case LPP_CURRENT: - r.readCurrent(v); - strcpy(name, "current"); sprintf(buf, "%.3f", v); - break; - case LPP_TEMPERATURE: - r.readTemperature(v); - strcpy(name, "temperature"); sprintf(buf, "%.2f", v); - break; - case LPP_RELATIVE_HUMIDITY: - r.readRelativeHumidity(v); - strcpy(name, "humidity"); sprintf(buf, "%.2f", v); - break; - case LPP_BAROMETRIC_PRESSURE: - r.readPressure(v); - strcpy(name, "pressure"); sprintf(buf, "%.2f", v); - break; - case LPP_ALTITUDE: - r.readAltitude(v); - strcpy(name, "altitude"); sprintf(buf, "%.0f", v); - break; - case LPP_POWER: - r.readPower(v); - strcpy(name, "power"); sprintf(buf, "%6.2f", v); - break; - default: - r.skipData(type); - strcpy(name, "unk"); sprintf(buf, ""); - } display.setCursor(0, y); display.print(name); - display.setCursor( - display.width()-display.getTextWidth(buf)-1, y - ); + display.setCursor(display.width() - display.getTextWidth(buf) - 1, y); display.print(buf); - y = y + 12; + y += 12; } - if (sensors_scroll) sensors_scroll_offset = (sensors_scroll_offset+1)%sensors_nb; + if (need_scroll) sensors_scroll_offset = (sensors_scroll_offset + 1) % avail_count; else sensors_scroll_offset = 0; #endif } else if (_page == HomePage::SETTINGS) { diff --git a/src/helpers/SensorManager.h b/src/helpers/SensorManager.h index 89a174c2..a1ca4306 100644 --- a/src/helpers/SensorManager.h +++ b/src/helpers/SensorManager.h @@ -23,6 +23,7 @@ public: virtual const char* getSettingValue(int i) const { return NULL; } virtual bool setSettingValue(const char* name, const char* value) { return false; } virtual LocationProvider* getLocationProvider() { return NULL; } + virtual int getAvailableLPPTypes(uint8_t* types, int max_count) const { return 0; } // Helper functions to manage setting by keys (useful in many places ...) const char* getSettingByKey(const char* key) { diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 19472406..3e421944 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -540,6 +540,46 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } +int EnvironmentSensorManager::getAvailableLPPTypes(uint8_t* types, int max_count) const { + int n = 0; + auto add = [&](uint8_t t) { if (n < max_count) types[n++] = t; }; + + add(LPP_VOLTAGE); // battery voltage — always present + +#if ENV_INCLUDE_GPS + add(LPP_GPS); +#endif + + bool has_temp = AHTX0_initialized || BME680_initialized || BME280_initialized || + BMP280_initialized || SHTC3_initialized || SHT4X_initialized || + LPS22HB_initialized || MLX90614_initialized || BMP085_initialized || + RAK12035_initialized; + if (has_temp) add(LPP_TEMPERATURE); + + bool has_hum = AHTX0_initialized || BME680_initialized || BME280_initialized || + SHTC3_initialized || SHT4X_initialized || RAK12035_initialized; + if (has_hum) add(LPP_RELATIVE_HUMIDITY); + + bool has_press = BME680_initialized || LPS22HB_initialized; + if (has_press) add(LPP_BAROMETRIC_PRESSURE); + + bool has_alt = BME680_initialized || BME280_initialized || BMP280_initialized || BMP085_initialized; + if (has_alt) add(LPP_ALTITUDE); + + bool has_power = INA3221_initialized || INA219_initialized || INA260_initialized || INA226_initialized; + if (has_power) { add(LPP_CURRENT); add(LPP_POWER); } + +#if ENV_INCLUDE_VL53L0X + if (VL53L0X_initialized) add(LPP_DISTANCE); +#endif + +#if ENV_INCLUDE_RAK12035 + if (RAK12035_initialized) add(LPP_PERCENTAGE); +#endif + + return n; +} + int EnvironmentSensorManager::getNumSettings() const { int settings = 0; #if ENV_INCLUDE_GPS diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 32413ebc..dea329ad 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -49,6 +49,7 @@ public: #endif bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + int getAvailableLPPTypes(uint8_t* types, int max_count) const override; #if ENV_INCLUDE_GPS void loop() override; #endif diff --git a/src/helpers/sensors/LPPDataHelpers.h b/src/helpers/sensors/LPPDataHelpers.h index 37b50f3f..964395da 100644 --- a/src/helpers/sensors/LPPDataHelpers.h +++ b/src/helpers/sensors/LPPDataHelpers.h @@ -136,6 +136,22 @@ public: m = getFloat(&_buf[_pos], 2, 1, true); _pos += 2; return _pos <= _len; } + bool readLuminosity(float& lux) { + lux = getFloat(&_buf[_pos], 2, 1, false); _pos += 2; + return _pos <= _len; + } + bool readPercentage(float& pct) { + pct = getFloat(&_buf[_pos], 1, 1, false); _pos += 1; + return _pos <= _len; + } + bool readConcentration(float& ppm) { + ppm = getFloat(&_buf[_pos], 2, 1, false); _pos += 2; + return _pos <= _len; + } + bool readDistance(float& m) { + m = getFloat(&_buf[_pos], 4, 1000, false); _pos += 4; + return _pos <= _len; + } void skipData(uint8_t type) { switch (type) {