From cb557d89a636dce210af9288453b15fe76edbf23 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Tue, 11 Aug 2026 18:28:40 +0200 Subject: [PATCH] Multi one wire measurements (#10192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First version of DS248X bridge * Add first iteration of DS248X sensor * Supports single readings on DS2484 * Supports readings on ch0 for DS2484_800 * Detection of variant for DS248X * Minor fix on retries for sensor init * Allow multiple channel detect passes on 8-ch version * Always read temperature via ROM matching * Small comment to show how to send all channels * Minor logging changes * Prevent one-wire double definitions * Detect ROMs per round * Fix comment * Prevent skipping on DS2482 ALT3 check * Fix comment (again) * Fix style checks * Remove comment for multiple measurements * Add multi-sensor measurements for one-wire sensors using wildcard message * Move to unpacked measurements in one-wire * Add admin command to set main temperature in 8-channel one-wire bridge. * Fix merge ref * Trunk fmt * Remove unused variable --------- Co-authored-by: Thomas Göttgens --- platformio.ini | 12 +- src/detect/ScanI2CTwoWire.cpp | 1 - src/modules/Telemetry/Sensor/DS248XSensor.cpp | 117 ++++++++++++++++-- src/modules/Telemetry/Sensor/DS248XSensor.h | 5 + 4 files changed, 122 insertions(+), 13 deletions(-) diff --git a/platformio.ini b/platformio.ini index f3ae026f6..76b00c1f7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -247,8 +247,18 @@ lib_deps = closedcube/ClosedCube OPT3001@1.1.2 # renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip + # renovate: datasource=github-tags depName=Sensirion Core packageName=sensirion/arduino-core + https://github.com/Sensirion/arduino-core/archive/refs/tags/0.7.3.zip + # renovate: datasource=github-tags depName=Sensirion I2C SCD4x packageName=sensirion/arduino-i2c-scd4x + https://github.com/Sensirion/arduino-i2c-scd4x/archive/refs/tags/1.1.0.zip + # renovate: datasource=github-tags depName=Sensirion I2C SFA3x packageName=sensirion/arduino-i2c-sfa3x + https://github.com/Sensirion/arduino-i2c-sfa3x/archive/refs/tags/1.0.0.zip + # renovate: datasource=github-tags depName=Sensirion I2C SCD30 packageName=sensirion/arduino-i2c-scd30 + https://github.com/Sensirion/arduino-i2c-scd30/archive/1.1.1.zip + # renovate: datasource=github-tags depName=arduino-sht packageName=sensirion/arduino-sht + https://github.com/Sensirion/arduino-sht/archive/refs/tags/v1.2.6.zip # renovate: datasource=github-tags depName=Adafruit DS248x packageName=adafruit/Adafruit_DS248x - https://github.com/adafruit/Adafruit_DS248x/archive/refs/tags/1.2.0.zip + https://github.com/adafruit/Adafruit_DS248x/archive/refs/tags/1.2.0.zip ; Environmental sensors with BSEC2 (Bosch proprietary IAQ) [environmental_extra] diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 0aa2301e3..21a74b759 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -743,7 +743,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("DS2482-800", (uint8_t)addr.address); break; } - type = HMC5883L; logFoundDevice("HMC5883L", (uint8_t)addr.address); break; diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index a660700fc..f3158d432 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -78,7 +78,6 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) // Try to init One-Wire with 3 retries. This detects ROMs consistently // on the second one. uint8_t numRetries = 3; - uint8_t rom[8]{}; for (uint8_t retry = 1; retry <= numRetries; retry++) { bool initError = false; @@ -162,12 +161,14 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) } if (!initError) { - LOG_INFO("%s: Started one-wire (%u/%u)", sensorName, retry, numRetries); status = true; // We want to keep searching for ROMs on the DS248X_DS2482_800 // and always do the three passes if (_variant == ds248x_variant_t::DS248X_DS2484) { + LOG_INFO("%s: Started one-wire (%u/%u)", sensorName, retry, numRetries); break; + } else { + LOG_INFO("%s: One-wire startup cycle (%u/%u)", sensorName, retry, numRetries); } } // TODO Potentially not needed, but taken from Adafruit's library example @@ -282,18 +283,112 @@ bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) return true; } } else if (_variant == ds248x_variant_t::DS248X_DS2482_800) { - // Only ch0 is reported, and each populated channel blocks 750ms on its conversion - // TODO Support more than one temperature via repeated (3.0) - // TODO Select which channel can be reported as main temperature - if (readTemperatureChannel(0)) { - measurement->variant.environment_metrics.temperature = ds2482800Data.ds248xData[0].temperature; - measurement->variant.environment_metrics.has_temperature = true; - LOG_DEBUG("Got %s readings: temperature=%.2f", sensorName, measurement->variant.environment_metrics.temperature); - return true; + // If using DS248X_DS2482_800, we read all channels + uint8_t channelCount = 0; + + // Note, the reason why we are using an unpacked version of this message + // (instead of repeated) it's to save space. With repeated, we have to send all + // channels (even if null) or otherwise we don't know where each channel is + // being reported + for (uint8_t channel = 0; channel < 8; channel++) { + if (readTemperatureChannel(channel)) { + channelCount += 1; + + if (channel == mainTemperatureChannel) { + measurement->variant.environment_metrics.has_temperature = true; + measurement->variant.environment_metrics.temperature = ds2482800Data.ds248xData[channel].temperature; + } + + switch (channel) { + case 0: + measurement->variant.environment_metrics.has_one_wire_temperature_ch0 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch0 = + ds2482800Data.ds248xData[channel].temperature; + break; + case 1: + measurement->variant.environment_metrics.has_one_wire_temperature_ch1 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch1 = + ds2482800Data.ds248xData[channel].temperature; + break; + case 2: + measurement->variant.environment_metrics.has_one_wire_temperature_ch2 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch2 = + ds2482800Data.ds248xData[channel].temperature; + break; + case 3: + measurement->variant.environment_metrics.has_one_wire_temperature_ch3 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch3 = + ds2482800Data.ds248xData[channel].temperature; + break; + case 4: + measurement->variant.environment_metrics.has_one_wire_temperature_ch4 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch4 = + ds2482800Data.ds248xData[channel].temperature; + break; + case 5: + measurement->variant.environment_metrics.has_one_wire_temperature_ch5 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch5 = + ds2482800Data.ds248xData[channel].temperature; + break; + case 6: + measurement->variant.environment_metrics.has_one_wire_temperature_ch6 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch6 = + ds2482800Data.ds248xData[channel].temperature; + break; + case 7: + measurement->variant.environment_metrics.has_one_wire_temperature_ch7 = true; + measurement->variant.environment_metrics.one_wire_temperature_ch7 = + ds2482800Data.ds248xData[channel].temperature; + break; + } + + LOG_DEBUG("Got %s readings: temperature_ch%u=%.2f", sensorName, channel, + ds2482800Data.ds248xData[channel].temperature); + } } - return false; + return channelCount > 0; } return false; } +void DS248XSensor::setMainTemperature(uint8_t channel) +{ + if (channel > 7) { + LOG_ERROR("%s: Requested channel (%u) not available", sensorName, channel); + return; + } + + LOG_INFO("%s: Setting requested channel (%u) as main temperature", sensorName, channel); + mainTemperatureChannel = channel; + return; +} + +AdminMessageHandleResult DS248XSensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) +{ + AdminMessageHandleResult result; + result = AdminMessageHandleResult::NOT_HANDLED; + + switch (request->which_payload_variant) { + case meshtastic_AdminMessage_sensor_config_tag: + if (!request->sensor_config.has_ds248x_config) { + result = AdminMessageHandleResult::NOT_HANDLED; + break; + } + + // Check for main temperature channel request + if (request->sensor_config.ds248x_config.has_main_temperature_channel) { + this->setMainTemperature(request->sensor_config.ds248x_config.main_temperature_channel); + } + + result = AdminMessageHandleResult::HANDLED; + break; + + default: + result = AdminMessageHandleResult::NOT_HANDLED; + } + + return result; +} + #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.h b/src/modules/Telemetry/Sensor/DS248XSensor.h index bfe18a035..f1215149c 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.h +++ b/src/modules/Telemetry/Sensor/DS248XSensor.h @@ -66,6 +66,7 @@ class DS248XSensor : public TelemetrySensor ds248x_variant_t _variant = DS248X_UNKNOWN; _DS248XData ds248xData{}; _DS2482800Data ds2482800Data{}; + uint8_t mainTemperatureChannel = 0; #ifdef DS248X_I2C_CLOCK_SPEED ReClockI2C reClockI2C; #endif @@ -73,12 +74,16 @@ class DS248XSensor : public TelemetrySensor bool isValidROM(const uint8_t *rom); float readTemperatureROM(const uint8_t *rom); bool readTemperatureChannel(uint8_t channel); + void setMainTemperature(uint8_t channel); public: DS248XSensor(); ds248x_variant_t detectVariant(); virtual bool getMetrics(meshtastic_Telemetry *measurement) override; virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; + + AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) override; }; #endif \ No newline at end of file