From fc3ff77dc70f9b6f080f832aac3e9f6f0f6a5146 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sat, 4 Apr 2026 19:25:40 +0200 Subject: [PATCH 01/15] First version of DS248X bridge --- platformio.ini | 2 ++ src/configuration.h | 1 + src/detect/ScanI2C.h | 3 ++- src/detect/ScanI2CTwoWire.cpp | 10 +++++++++- src/modules/Telemetry/EnvironmentTelemetry.cpp | 8 ++++++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 06cc6e583ef..59556173b9f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -215,6 +215,8 @@ lib_deps = sensirion/Sensirion I2C SCD30@1.0.0 # renovate: datasource=custom.pio depName=arduino-sht packageName=sensirion/library/arduino-sht sensirion/arduino-sht@1.2.6 + # renovate: datasource=github-tags depName=Adafruit DS248x packageName=adafruit/Adafruit_DS248x + adafruit/Adafruit DS248x@1.2.0 ; Environmental sensors with BSEC2 (Bosch proprietary IAQ) [environmental_extra] diff --git a/src/configuration.h b/src/configuration.h index 84dabee4e83..84fcdd60f66 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -271,6 +271,7 @@ along with this program. If not, see . #define LTR553ALS_ADDR 0x23 #define SEN5X_ADDR 0x69 #define SCD30_ADDR 0x61 +#define DS248X_ADDR 0x18 // ----------------------------------------------------------------------------- // ACCELEROMETER diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index d451d394836..67892e7d523 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -92,7 +92,8 @@ class ScanI2C CW2015, SCD30, ADS1115, - SHTXX + SHTXX, + DS248X } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 052b2245a1b..08b37396037 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -478,7 +478,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) break; } #endif - // Check register 0x07 for 0x0400 response to ID MCP9808 chip. registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2); if (registerValue == 0x0400) { @@ -492,6 +491,15 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 type = LIS3DH; logFoundDevice("LIS3DH", (uint8_t)addr.address); + break; + } + + // Check register 0xF0 for DS284X status and one-wire busy + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + LOG_DEBUG("register value 0x%x", registerValue); + if (registerValue & 0x01) { // RAK4631 WisBlock has LIS3DH register at 0x3333 + type = DS248X; + logFoundDevice("DS248X", (uint8_t)addr.address); } break; } diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 684d408a1cc..db70da31144 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -131,6 +131,10 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c #include "Sensor/BH1750Sensor.h" #endif +#if __has_include() +#include "Sensor/DS248XSensor.h" +#endif + #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -240,6 +244,10 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) // TODO Can we scan for multiple sensors connected on the same bus? addSensor(i2cScanner, ScanI2C::DeviceType::SHTXX); #endif +#if __has_include() + addSensor(i2cScanner, ScanI2C::DeviceType::DS248X); +#endif + #endif } From 51ee30d6998e5eac7909ea0453e7e5c3504a1cef Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sat, 4 Apr 2026 23:35:02 +0200 Subject: [PATCH 02/15] Add first iteration of DS248X sensor * Supports single readings on DS2484 * Supports readings on ch0 for DS2484_800 * Detection of variant for DS248X --- src/configuration.h | 9 +- src/detect/ScanI2CTwoWire.cpp | 86 ++++++- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 239 ++++++++++++++++++ src/modules/Telemetry/Sensor/DS248XSensor.h | 57 +++++ 4 files changed, 379 insertions(+), 12 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/DS248XSensor.cpp create mode 100644 src/modules/Telemetry/Sensor/DS248XSensor.h diff --git a/src/configuration.h b/src/configuration.h index 84fcdd60f66..963686b3d93 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -271,7 +271,14 @@ along with this program. If not, see . #define LTR553ALS_ADDR 0x23 #define SEN5X_ADDR 0x69 #define SCD30_ADDR 0x61 -#define DS248X_ADDR 0x18 +#define DS248X_ADDR 0x18 // same as MCP9808_ADDR, STK8BXX_ADDR and LIS3DH_ADDR +#define DS248X_ADDR_ALT1 0x19 // same as LIS3DH_ADDR_ALT and BMA423_ADDR +#define DS248X_ADDR_ALT2 0x1A // same as CST328_ADDR +#define DS248X_ADDR_ALT3 0x1B +#define DS248X_ADDR_ALT4 0x1C // same as QMC6310U_ADDR +#define DS248X_ADDR_ALT5 0x1D // same as DFROBOT_RAIN_ADDR +#define DS248X_ADDR_ALT6 0x1E // same as HMC5883L_ADDR +#define DS248X_ADDR_ALT7 0x1F // same as BBQ10_KB_ADDR // ----------------------------------------------------------------------------- // ACCELEROMETER diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 08b37396037..0e64449afeb 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -338,8 +338,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) type = TDECKKB; } break; - SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address); - + case BBQ10_KB_ADDR: + // Check status register (0xF0) for DS284X status and one-wire reset + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + if (registerValue & 0x16) { // One-wire reset after power-on + type = DS248X; + logFoundDevice("DS2482-800", (uint8_t)addr.address); + break; + } + type = BBQ10KB; + logFoundDevice("BB Q10", (uint8_t)addr.address); + break; SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address); #ifdef HAS_NCP5623 SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address); @@ -494,10 +503,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) break; } - // Check register 0xF0 for DS284X status and one-wire busy + // Check status register (0xF0) for DS284X status and one-wire reset registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); - LOG_DEBUG("register value 0x%x", registerValue); - if (registerValue & 0x01) { // RAK4631 WisBlock has LIS3DH register at 0x3333 + if (registerValue & 0x16) { // One-wire reset after power-on type = DS248X; logFoundDevice("DS248X", (uint8_t)addr.address); } @@ -544,7 +552,26 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) } break; SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB", (uint8_t)addr.address) - SCAN_SIMPLE_CASE(QMC6310U_ADDR, QMC6310U, "QMC6310U", (uint8_t)addr.address) + case DS248X_ADDR_ALT3: + // Check status register (0xF0) for DS284X status and one-wire reset + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + if (registerValue & 0x16) { // One-wire reset after power-on + type = DS248X; + logFoundDevice("DS2482-800", (uint8_t)addr.address); + break; + } + + case QMC6310U_ADDR: + // Check status register (0xF0) for DS284X status and one-wire reset + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + if (registerValue & 0x16) { // One-wire reset after power-on + type = DS248X; + logFoundDevice("DS2482-800", (uint8_t)addr.address); + break; + } + type = QMC6310U; + logFoundDevice("QMC6310U", (uint8_t)addr.address); + break; case QMI8658_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0A), 1); // get ID @@ -570,7 +597,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) break; SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L", (uint8_t)addr.address) - SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L", (uint8_t)addr.address) + case HMC5883L_ADDR: + // Check status register (0xF0) for DS284X status and one-wire reset + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + if (registerValue & 0x16) { // One-wire reset after power-on + type = DS248X; + logFoundDevice("DS2482-800", (uint8_t)addr.address); + break; + } + type = HMC5883L; + logFoundDevice("HMC5883L", (uint8_t)addr.address); + break; #ifdef HAS_QMA6100P SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P", (uint8_t)addr.address) #else @@ -581,10 +618,20 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 type = LIS3DH; logFoundDevice("LIS3DH", (uint8_t)addr.address); - } else { - type = BMA423; - logFoundDevice("BMA423", (uint8_t)addr.address); + break; + } + + // Check status register (0xF0) for DS284X status and one-wire reset + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + if (registerValue & 0x16) { // One-wire reset after power-on + type = DS248X; + logFoundDevice("DS2482-800", (uint8_t)addr.address); + break; } + + type = BMA423; + logFoundDevice("BMA423", (uint8_t)addr.address); + break; case TCA9535_ADDR: case RAK120352_ADDR: @@ -632,11 +679,28 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address); SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address); SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address); - SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address); + case DFROBOT_RAIN_ADDR: + // Check status register (0xF0) for DS284X status and one-wire reset + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + if (registerValue & 0x16) { // One-wire reset after power-on + type = DS248X; + logFoundDevice("DS2482-800", (uint8_t)addr.address); + break; + } + type = DFROBOT_RAIN; + logFoundDevice("DFRobot Rain Gauge", (uint8_t)addr.address); + break; SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address); SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address); SCAN_SIMPLE_CASE(SCD30_ADDR, SCD30, "SCD30", (uint8_t)addr.address); case CST328_ADDR: + // Check status register (0xF0) for DS284X status and one-wire reset + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xF0), 1); + if (registerValue & 0x16) { // One-wire reset after power-on + type = DS248X; + logFoundDevice("DS2482-800", (uint8_t)addr.address); + break; + } // Do we have the CST328 or the CST226SE registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xAB), 1); if (registerValue == 0xA9) { diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp new file mode 100644 index 00000000000..a0e19d70a6e --- /dev/null +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -0,0 +1,239 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() + +#include "../detect/reClockI2C.h" +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "DS248XSensor.h" +#include "TelemetrySensor.h" +#include + +DS248XSensor::DS248XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DS248X, "DS248X") {} + +ds248x_variant_t DS248XSensor::detectVariant() +{ + + // Wait until idle + if (!ds248x.busyWait(1000)) { + return DS248X_UNKNOWN; + } + + // Try Channel Select command (only valid on DS2482-800) + if (!ds248x.selectChannel(0)) { + _variant = DS248X_DS2484; + } else { + _variant = DS248X_DS2482_800; + } + + return _variant; +} + +void DS248XSensor::printROM(uint8_t *rom) +{ + LOG_INFO("%s: ROM found - %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", sensorName, rom[0], rom[1], rom[2], rom[3], rom[4], + rom[5], rom[6], rom[7]); +} + +bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) +{ + _address = dev->address.address; + _bus = bus; + LOG_INFO("Init sensor: %s", sensorName); + +#ifdef DS248X_I2C_CLOCK_SPEED +#ifdef CAN_RECLOCK_I2C + uint32_t currentClock = reClockI2C(DS248X_I2C_CLOCK_SPEED, _bus, false); +#elif !HAS_SCREEN + reClockI2C(DS248X_I2C_CLOCK_SPEED, _bus, true); +#else + LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); + return false; +#endif /* CAN_RECLOCK_I2C */ +#endif /* DS248X_I2C_CLOCK_SPEED */ + + // #ifdef DS248X_I2C_CLOCK_SPEED + // uint32_t currentClock = reClockI2C(DS248X_I2C_CLOCK_SPEED, _bus, false); + // #endif /* DS248X_I2C_CLOCK_SPEED */ + + if (!ds248x.begin(bus, _address)) { +#if defined(DS248X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) + reClockI2C(currentClock, _bus, false); +#endif + return false; + } + + // Try to init One-Wire with max retries + uint8_t numRetries = 3; + uint8_t rom[8]{}; + for (uint8_t retry = 0; retry < numRetries; retry++) { + bool initError = false; + if (!ds248x.OneWireReset()) { + LOG_WARN("%s: One-wire reset unsuccessful (%u/%u)", sensorName, retry, numRetries); + initError = true; + } + + if (ds248x.shortDetected()) { + LOG_WARN("%s: One-wire short detected (%u/%u)", sensorName, retry, numRetries); + initError = true; + } + + if (!ds248x.presencePulseDetected()) { + LOG_WARN("%s: One-wire no presence pulse detected (%u/%u)", sensorName, retry, numRetries); + initError = true; + } + + // TODO - This will detect a ROM and will always read the same throughout runtime + // If someone connects more than one one-wire temperature sensor, currently it will + // only read the first one (we only have one temperature to report) + if (!ds248x.OneWireSearch(ds248xData.rom)) { + LOG_WARN("%s: no one-wire rom detected (%u/%u)", sensorName, retry, numRetries); + initError = true; + } else { + LOG_INFO("%s: One-wire rom detected (%u/%u)", sensorName, retry, numRetries); + printROM(ds248xData.rom); + } + + if (detectVariant() == DS248X_DS2482_800) { + LOG_INFO("%s: Multi-channel DS2482-800 detected", sensorName); + } else { + LOG_INFO("%s: Single-channel DS2484 detected", sensorName); + } + + if (initError && retry == numRetries - 1) { +#if defined(DS248X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) + reClockI2C(currentClock, _bus, false); +#endif + LOG_WARN("%s: Max retries for one-wire init (%u/%u). Aborting", sensorName, retry, numRetries); + return false; + } + + if (!initError) { + LOG_INFO("%s: Started one-wire (%u/%u)", sensorName, retry, numRetries); + status = true; + break; + } + delay(500); + } + + initI2CSensor(); + return status; +} + +// Read a one-wire temperature sensor by matching it's ROM +bool DS248XSensor::readTemperatureROM(uint8_t *rom) +{ +#ifdef DS248X_I2C_CLOCK_SPEED +#ifdef CAN_RECLOCK_I2C + uint32_t currentClock = reClockI2C(DS248X_I2C_CLOCK_SPEED, _bus, false); +#elif !HAS_SCREEN + reClockI2C(DS248X_I2C_CLOCK_SPEED, _bus, true); +#else + LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); + return false; +#endif /* CAN_RECLOCK_I2C */ +#endif /* DS248X_I2C_CLOCK_SPEED */ + + // #ifdef DS248X_I2C_CLOCK_SPEED + // uint32_t currentClock = reClockI2C(DS248X_I2C_CLOCK_SPEED, _bus, false); + // #endif /* DS248X_I2C_CLOCK_SPEED */ + + // Select the DS18B20 device + ds248x.OneWireReset(); + ds248x.OneWireWriteByte(DS18B20_CMD_MATCH_ROM); // Match ROM command + for (int i = 0; i < 8; i++) { + ds248x.OneWireWriteByte(rom[i]); + } + + // Start temperature conversion + ds248x.OneWireWriteByte(DS18B20_CMD_CONVERT_T); // Convert T command + delay(750); // Wait for conversion (750ms for maximum precision) + + // Read scratchpad + ds248x.OneWireReset(); + ds248x.OneWireWriteByte(DS18B20_CMD_MATCH_ROM); // Match ROM command + for (int i = 0; i < 8; i++) { + ds248x.OneWireWriteByte(rom[i]); + } + ds248x.OneWireWriteByte(DS18B20_CMD_READ_SCRATCHPAD); // Read Scratchpad command + + uint8_t data[9]; + for (int i = 0; i < 9; i++) { + ds248x.OneWireReadByte(&data[i]); + } + +#if defined(DS248X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) + reClockI2C(currentClock, _bus, false); +#endif + + // Calculate temperature + int16_t raw = (data[1] << 8) | data[0]; + float celsius = (float)raw / 16.0; + + ds248xData.temperature = celsius; + return true; +} + +bool DS248XSensor::readTemperatureChannel(uint8_t channel) +{ + // Select the channel on the DS2482-800 + if (!ds248x.selectChannel(channel)) { + // Handle error if channel selection fails + LOG_WARN("%s: Failed to select channel %u", sensorName, channel); + return false; + } + + // Start temperature conversion + ds248x.OneWireReset(); + ds248x.OneWireWriteByte(DS18B20_CMD_SKIP_ROM); // Skip ROM command + ds248x.OneWireWriteByte(DS18B20_CMD_CONVERT_T); // Convert T command + delay(750); // Wait for conversion (750ms for maximum precision) + + // Read scratchpad + ds248x.OneWireReset(); + ds248x.OneWireWriteByte(DS18B20_CMD_SKIP_ROM); // Skip ROM command + ds248x.OneWireWriteByte(DS18B20_CMD_READ_SCRATCHPAD); // Read Scratchpad command + + uint8_t data[9]; + for (int i = 0; i < 9; i++) { + ds248x.OneWireReadByte(&data[i]); + } + + // Calculate temperature + int16_t raw = (data[1] << 8) | data[0]; + float celsius = (float)raw / 16.0; + + ds2482800Data.ds248xData[channel].temperature = celsius; + LOG_DEBUG("%s: read temperature in channel %u: %0.2f", sensorName, channel, celsius); + return true; +} + +bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) +{ + if (_variant == ds248x_variant_t::DS248X_DS2484) { + if (readTemperatureROM(ds248xData.rom)) { + measurement->variant.environment_metrics.temperature = ds248xData.temperature; + measurement->variant.environment_metrics.has_temperature = true; + LOG_DEBUG("Got %s readings: temperature=%.2f", sensorName, measurement->variant.environment_metrics.temperature); + return true; + } + } else if (_variant == ds248x_variant_t::DS248X_DS2482_800) { + // If using DS248X_DS2482_800, we read all channels, but we will only report ch0 + bool readChannel0 = false; + for (uint8_t channel = 0; channel < 8; channel++) { + if (readTemperatureChannel(channel)) { + // TODO Support more than one temperature via repeated (3.0) + if (channel == 0) { + readChannel0 = true; + 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 readChannel0; + } + return false; +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.h b/src/modules/Telemetry/Sensor/DS248XSensor.h new file mode 100644 index 00000000000..70c73ffc7d5 --- /dev/null +++ b/src/modules/Telemetry/Sensor/DS248XSensor.h @@ -0,0 +1,57 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include + +#ifndef DS248X_I2C_CLOCK_SPEED +#define DS248X_I2C_CLOCK_SPEED 400000 +#endif + +#define DS18B20_CMD_SKIP_ROM 0xCC +#define DS18B20_CMD_CONVERT_T 0x44 +#define DS18B20_CMD_READ_SCRATCHPAD 0xBE + +#define DS18B20_FAMILY_CODE 0x28 +#define DS18B20_CMD_CONVERT_T 0x44 +#define DS18B20_CMD_MATCH_ROM 0x55 +#define DS18B20_CMD_READ_SCRATCHPAD 0xBE + +#define DS248X_CMD_CHANNEL_SELECT 0xC3 +#define DS248X_REG_CHANNEL 0xD2 +#define DS248X_CH0 0xF0 + +typedef enum { DS248X_UNKNOWN = 0, DS248X_DS2484, DS248X_DS2482_800 } ds248x_variant_t; + +struct _DS248XData { + uint8_t rom[8]; + float temperature; +}; + +struct _DS2482800Data { + _DS248XData ds248xData[8]; +}; + +class DS248XSensor : public TelemetrySensor +{ + private: + Adafruit_DS248x ds248x; + TwoWire *_bus{}; + uint8_t _address{}; + ds248x_variant_t _variant = DS248X_UNKNOWN; + _DS248XData ds248xData{}; + _DS2482800Data ds2482800Data{}; + void printROM(uint8_t *rom); + bool readTemperatureROM(uint8_t *rom); + bool readTemperatureChannel(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; +}; + +#endif \ No newline at end of file From 2ab2f0122d378722d9107231722b19cfb4d1f79d Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 5 Apr 2026 15:20:26 +0200 Subject: [PATCH 03/15] Minor fix on retries for sensor init --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index a0e19d70a6e..5d98d2f4dc5 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -65,7 +65,7 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) // Try to init One-Wire with max retries uint8_t numRetries = 3; uint8_t rom[8]{}; - for (uint8_t retry = 0; retry < numRetries; retry++) { + for (uint8_t retry = 1; retry <= numRetries; retry++) { bool initError = false; if (!ds248x.OneWireReset()) { LOG_WARN("%s: One-wire reset unsuccessful (%u/%u)", sensorName, retry, numRetries); @@ -99,7 +99,7 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) LOG_INFO("%s: Single-channel DS2484 detected", sensorName); } - if (initError && retry == numRetries - 1) { + if (initError && retry == numRetries) { #if defined(DS248X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) reClockI2C(currentClock, _bus, false); #endif From 68c05e7752b6eabf02fd602f2b7201c38616d593 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 5 Apr 2026 19:41:54 +0200 Subject: [PATCH 04/15] Allow multiple channel detect passes on 8-ch version * Always read temperature via ROM matching --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 136 +++++++++++------- src/modules/Telemetry/Sensor/DS248XSensor.h | 5 +- 2 files changed, 87 insertions(+), 54 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index 5d98d2f4dc5..5802935f22d 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -62,41 +62,73 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) return false; } - // Try to init One-Wire with max retries + // Try to init One-Wire with 3 retries. This detects ROMs consistently + // on the second one. uint8_t numRetries = 3; + uint8_t nROMDetected = 0; uint8_t rom[8]{}; + for (uint8_t retry = 1; retry <= numRetries; retry++) { bool initError = false; - if (!ds248x.OneWireReset()) { - LOG_WARN("%s: One-wire reset unsuccessful (%u/%u)", sensorName, retry, numRetries); - initError = true; - } - if (ds248x.shortDetected()) { - LOG_WARN("%s: One-wire short detected (%u/%u)", sensorName, retry, numRetries); - initError = true; - } + if (detectVariant() == DS248X_DS2482_800) { - if (!ds248x.presencePulseDetected()) { - LOG_WARN("%s: One-wire no presence pulse detected (%u/%u)", sensorName, retry, numRetries); - initError = true; - } + LOG_INFO("%s: Multi-channel DS2482-800 detected", sensorName); - // TODO - This will detect a ROM and will always read the same throughout runtime - // If someone connects more than one one-wire temperature sensor, currently it will - // only read the first one (we only have one temperature to report) - if (!ds248x.OneWireSearch(ds248xData.rom)) { - LOG_WARN("%s: no one-wire rom detected (%u/%u)", sensorName, retry, numRetries); - initError = true; - } else { - LOG_INFO("%s: One-wire rom detected (%u/%u)", sensorName, retry, numRetries); - printROM(ds248xData.rom); - } + for (uint8_t channel = 0; channel < 8; channel++) { + + if (ds248x.selectChannel(channel)) { + + ds248x.OneWireReset(); + + if (!ds248x.OneWireSearch(ds2482800Data.ds248xData[channel].rom)) { + LOG_WARN("%s: no one-wire rom detected on channel %u (%u/%u)", sensorName, channel, retry, numRetries); + for (uint8_t i = 0; i < 8; i++) { + ds2482800Data.ds248xData[channel].rom[i] = 0; + } + } else { + LOG_INFO("%s: One-wire rom detected on channel %u (%u/%u)", sensorName, channel, retry, numRetries); + printROM(ds2482800Data.ds248xData[channel].rom); + nROMDetected += 1; + } + + } else { + LOG_WARN("%s: Failed to select channel %u", sensorName, channel); + } + } + + if (!nROMDetected) { + initError = true; + } - if (detectVariant() == DS248X_DS2482_800) { - LOG_INFO("%s: Multi-channel DS2482-800 detected", sensorName); } else { LOG_INFO("%s: Single-channel DS2484 detected", sensorName); + + if (!ds248x.OneWireReset()) { + LOG_WARN("%s: One-wire reset unsuccessful (%u/%u)", sensorName, retry, numRetries); + initError = true; + } + + if (ds248x.shortDetected()) { + LOG_WARN("%s: One-wire short detected (%u/%u)", sensorName, retry, numRetries); + initError = true; + } + + if (!ds248x.presencePulseDetected()) { + LOG_WARN("%s: One-wire no presence pulse detected (%u/%u)", sensorName, retry, numRetries); + initError = true; + } + + // TODO - This will detect a ROM and will always read the same throughout runtime for the DS2484 + // If someone connects more than one one-wire temperature sensor, currently it will + // only read the first one (we only have one temperature to report) + if (!ds248x.OneWireSearch(ds248xData.rom)) { + LOG_WARN("%s: no one-wire rom detected (%u/%u)", sensorName, retry, numRetries); + initError = true; + } else { + LOG_INFO("%s: One-wire rom detected (%u/%u)", sensorName, retry, numRetries); + printROM(ds248xData.rom); + } } if (initError && retry == numRetries) { @@ -110,8 +142,13 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) if (!initError) { LOG_INFO("%s: Started one-wire (%u/%u)", sensorName, retry, numRetries); status = true; - break; + // 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) { + break; + } } + // TODO Potentially not needed, but taken from Adafruit's library example delay(500); } @@ -119,8 +156,13 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) return status; } +bool DS248XSensor::isValidROM(uint8_t *rom) +{ + return (rom[0] || rom[1] || rom[2] || rom[3] || rom[4] || rom[5] || rom[6] || rom[7]); +} + // Read a one-wire temperature sensor by matching it's ROM -bool DS248XSensor::readTemperatureROM(uint8_t *rom) +float DS248XSensor::readTemperatureROM(uint8_t *rom) { #ifdef DS248X_I2C_CLOCK_SPEED #ifdef CAN_RECLOCK_I2C @@ -129,7 +171,7 @@ bool DS248XSensor::readTemperatureROM(uint8_t *rom) reClockI2C(DS248X_I2C_CLOCK_SPEED, _bus, true); #else LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName); - return false; + return -1000.0; #endif /* CAN_RECLOCK_I2C */ #endif /* DS248X_I2C_CLOCK_SPEED */ @@ -169,12 +211,15 @@ bool DS248XSensor::readTemperatureROM(uint8_t *rom) int16_t raw = (data[1] << 8) | data[0]; float celsius = (float)raw / 16.0; - ds248xData.temperature = celsius; - return true; + return celsius; } bool DS248XSensor::readTemperatureChannel(uint8_t channel) { + if (!isValidROM(ds2482800Data.ds248xData[channel].rom)) { + LOG_WARN("%s: No ROM in channel %u", sensorName, channel); + return false; + } // Select the channel on the DS2482-800 if (!ds248x.selectChannel(channel)) { // Handle error if channel selection fails @@ -182,36 +227,22 @@ bool DS248XSensor::readTemperatureChannel(uint8_t channel) return false; } - // Start temperature conversion - ds248x.OneWireReset(); - ds248x.OneWireWriteByte(DS18B20_CMD_SKIP_ROM); // Skip ROM command - ds248x.OneWireWriteByte(DS18B20_CMD_CONVERT_T); // Convert T command - delay(750); // Wait for conversion (750ms for maximum precision) + float temperature; + temperature = readTemperatureROM(ds2482800Data.ds248xData[channel].rom); - // Read scratchpad - ds248x.OneWireReset(); - ds248x.OneWireWriteByte(DS18B20_CMD_SKIP_ROM); // Skip ROM command - ds248x.OneWireWriteByte(DS18B20_CMD_READ_SCRATCHPAD); // Read Scratchpad command - - uint8_t data[9]; - for (int i = 0; i < 9; i++) { - ds248x.OneWireReadByte(&data[i]); + if (temperature != -1000.0) { + ds2482800Data.ds248xData[channel].temperature = temperature; + LOG_DEBUG("%s: read temperature in channel %u: %0.2f", sensorName, channel, temperature); } - - // Calculate temperature - int16_t raw = (data[1] << 8) | data[0]; - float celsius = (float)raw / 16.0; - - ds2482800Data.ds248xData[channel].temperature = celsius; - LOG_DEBUG("%s: read temperature in channel %u: %0.2f", sensorName, channel, celsius); return true; } bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) { if (_variant == ds248x_variant_t::DS248X_DS2484) { - if (readTemperatureROM(ds248xData.rom)) { - measurement->variant.environment_metrics.temperature = ds248xData.temperature; + float temperature = readTemperatureROM(ds248xData.rom); + if (temperature != -1000.0) { + measurement->variant.environment_metrics.temperature = temperature; measurement->variant.environment_metrics.has_temperature = true; LOG_DEBUG("Got %s readings: temperature=%.2f", sensorName, measurement->variant.environment_metrics.temperature); return true; @@ -222,6 +253,7 @@ bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) for (uint8_t channel = 0; channel < 8; channel++) { if (readTemperatureChannel(channel)) { // TODO Support more than one temperature via repeated (3.0) + // TODO Select which channel can be reported as main temperature if (channel == 0) { readChannel0 = true; measurement->variant.environment_metrics.temperature = ds2482800Data.ds248xData[0].temperature; diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.h b/src/modules/Telemetry/Sensor/DS248XSensor.h index 70c73ffc7d5..7d7492dad15 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.h +++ b/src/modules/Telemetry/Sensor/DS248XSensor.h @@ -26,7 +26,7 @@ typedef enum { DS248X_UNKNOWN = 0, DS248X_DS2484, DS248X_DS2482_800 } ds248x_variant_t; struct _DS248XData { - uint8_t rom[8]; + uint8_t rom[8] = {0, 0, 0, 0, 0, 0, 0, 0}; float temperature; }; @@ -44,7 +44,8 @@ class DS248XSensor : public TelemetrySensor _DS248XData ds248xData{}; _DS2482800Data ds2482800Data{}; void printROM(uint8_t *rom); - bool readTemperatureROM(uint8_t *rom); + bool isValidROM(uint8_t *rom); + float readTemperatureROM(uint8_t *rom); bool readTemperatureChannel(uint8_t channel); public: From 030d3fc2186b572885878c69d758fb3399576a5f Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 5 Apr 2026 20:00:49 +0200 Subject: [PATCH 05/15] Small comment to show how to send all channels --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index 5802935f22d..6651a371684 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -261,6 +261,10 @@ bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) LOG_DEBUG("Got %s readings: temperature=%.2f", sensorName, measurement->variant.environment_metrics.temperature); } + // measurement->variant.environment_metrics.one_wire_temperature[channel] = + // ds2482800Data.ds248xData[channel].temperature; LOG_DEBUG("Got %s readings: temperature_ch%u=%.2f", sensorName, + // channel, + // measurement->variant.environment_metrics.one_wire_temperature[channel]); } } return readChannel0; From abc17a314838314c7e2dfae5c4be6070ca584ec4 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 5 Apr 2026 21:03:59 +0200 Subject: [PATCH 06/15] Minor logging changes --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index 6651a371684..d9bf860537f 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -82,7 +82,7 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) ds248x.OneWireReset(); if (!ds248x.OneWireSearch(ds2482800Data.ds248xData[channel].rom)) { - LOG_WARN("%s: no one-wire rom detected on channel %u (%u/%u)", sensorName, channel, retry, numRetries); + LOG_DEBUG("%s: no one-wire rom detected on channel %u (%u/%u)", sensorName, channel, retry, numRetries); for (uint8_t i = 0; i < 8; i++) { ds2482800Data.ds248xData[channel].rom[i] = 0; } @@ -135,7 +135,7 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) #if defined(DS248X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C) reClockI2C(currentClock, _bus, false); #endif - LOG_WARN("%s: Max retries for one-wire init (%u/%u). Aborting", sensorName, retry, numRetries); + LOG_ERROR("%s: Max retries for one-wire init (%u/%u). Aborting", sensorName, retry, numRetries); return false; } @@ -217,7 +217,7 @@ float DS248XSensor::readTemperatureROM(uint8_t *rom) bool DS248XSensor::readTemperatureChannel(uint8_t channel) { if (!isValidROM(ds2482800Data.ds248xData[channel].rom)) { - LOG_WARN("%s: No ROM in channel %u", sensorName, channel); + LOG_DEBUG("%s: No ROM in channel %u", sensorName, channel); return false; } // Select the channel on the DS2482-800 From 4483d91590e8bf98c8a505f90042af7748f5ab32 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Mon, 6 Apr 2026 18:07:03 +0200 Subject: [PATCH 07/15] Prevent one-wire double definitions --- src/modules/Telemetry/Sensor/DS248XSensor.h | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.h b/src/modules/Telemetry/Sensor/DS248XSensor.h index 7d7492dad15..bcb92be166b 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.h +++ b/src/modules/Telemetry/Sensor/DS248XSensor.h @@ -10,18 +10,37 @@ #define DS248X_I2C_CLOCK_SPEED 400000 #endif +#ifndef DS18B20_CMD_SKIP_ROM #define DS18B20_CMD_SKIP_ROM 0xCC +#endif + +#ifndef DS18B20_CMD_CONVERT_T #define DS18B20_CMD_CONVERT_T 0x44 +#endif + +#ifndef DS18B20_CMD_READ_SCRATCHPAD #define DS18B20_CMD_READ_SCRATCHPAD 0xBE +#endif +#ifndef DS18B20_FAMILY_CODE #define DS18B20_FAMILY_CODE 0x28 -#define DS18B20_CMD_CONVERT_T 0x44 +#endif + +#ifndef DS18B20_CMD_MATCH_ROM #define DS18B20_CMD_MATCH_ROM 0x55 -#define DS18B20_CMD_READ_SCRATCHPAD 0xBE +#endif +#ifndef DS248X_CMD_CHANNEL_SELECT #define DS248X_CMD_CHANNEL_SELECT 0xC3 +#endif + +#ifndef DS248X_REG_CHANNEL #define DS248X_REG_CHANNEL 0xD2 +#endif + +#ifndef DS248X_CH0 #define DS248X_CH0 0xF0 +#endif typedef enum { DS248X_UNKNOWN = 0, DS248X_DS2484, DS248X_DS2482_800 } ds248x_variant_t; From 716176ecf33b03b81be7b6038e628f0bedeb9779 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Mon, 6 Apr 2026 18:07:35 +0200 Subject: [PATCH 08/15] Detect ROMs per round --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index d9bf860537f..de5e0e86a7e 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -65,11 +65,11 @@ 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 nROMDetected = 0; uint8_t rom[8]{}; for (uint8_t retry = 1; retry <= numRetries; retry++) { bool initError = false; + uint8_t nROMDetected = 0; if (detectVariant() == DS248X_DS2482_800) { From a97e8579d186b6e95d108540fdf7de703181d423 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Mon, 6 Apr 2026 18:08:13 +0200 Subject: [PATCH 09/15] Fix comment From 09b4de4ee09ab483ea76b3c9686efac24ee75e88 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Mon, 6 Apr 2026 18:08:43 +0200 Subject: [PATCH 10/15] Prevent skipping on DS2482 ALT3 check --- src/detect/ScanI2CTwoWire.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 0e64449afeb..ac54fcc5474 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -560,6 +560,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("DS2482-800", (uint8_t)addr.address); break; } + break; case QMC6310U_ADDR: // Check status register (0xF0) for DS284X status and one-wire reset From 3701d696797497aaf179267046a07d5e3a3a1a7f Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Mon, 6 Apr 2026 18:12:25 +0200 Subject: [PATCH 11/15] Fix comment (again) --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index de5e0e86a7e..c10939baf6d 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -262,9 +262,9 @@ bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) measurement->variant.environment_metrics.temperature); } // measurement->variant.environment_metrics.one_wire_temperature[channel] = - // ds2482800Data.ds248xData[channel].temperature; LOG_DEBUG("Got %s readings: temperature_ch%u=%.2f", sensorName, - // channel, - // measurement->variant.environment_metrics.one_wire_temperature[channel]); + // ds2482800Data.ds248xData[channel].temperature; + // LOG_DEBUG("Got %s readings: temperature_ch%u=%.2f", sensorName, channel, + // measurement->variant.environment_metrics.one_wire_temperature[channel]); } } return readChannel0; From c2b9bdc1aa743728b4732c959c5ec5c507f41885 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Wed, 15 Apr 2026 18:48:18 +0200 Subject: [PATCH 12/15] Fix style checks --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 6 +++--- src/modules/Telemetry/Sensor/DS248XSensor.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index c10939baf6d..069f386e21f 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -28,7 +28,7 @@ ds248x_variant_t DS248XSensor::detectVariant() return _variant; } -void DS248XSensor::printROM(uint8_t *rom) +void DS248XSensor::printROM(const uint8_t *rom) { LOG_INFO("%s: ROM found - %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", sensorName, rom[0], rom[1], rom[2], rom[3], rom[4], rom[5], rom[6], rom[7]); @@ -156,13 +156,13 @@ bool DS248XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) return status; } -bool DS248XSensor::isValidROM(uint8_t *rom) +bool DS248XSensor::isValidROM(const uint8_t *rom) { return (rom[0] || rom[1] || rom[2] || rom[3] || rom[4] || rom[5] || rom[6] || rom[7]); } // Read a one-wire temperature sensor by matching it's ROM -float DS248XSensor::readTemperatureROM(uint8_t *rom) +float DS248XSensor::readTemperatureROM(const uint8_t *rom) { #ifdef DS248X_I2C_CLOCK_SPEED #ifdef CAN_RECLOCK_I2C diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.h b/src/modules/Telemetry/Sensor/DS248XSensor.h index bcb92be166b..54924fef526 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.h +++ b/src/modules/Telemetry/Sensor/DS248XSensor.h @@ -62,9 +62,9 @@ class DS248XSensor : public TelemetrySensor ds248x_variant_t _variant = DS248X_UNKNOWN; _DS248XData ds248xData{}; _DS2482800Data ds2482800Data{}; - void printROM(uint8_t *rom); - bool isValidROM(uint8_t *rom); - float readTemperatureROM(uint8_t *rom); + void printROM(const uint8_t *rom); + bool isValidROM(const uint8_t *rom); + float readTemperatureROM(const uint8_t *rom); bool readTemperatureChannel(uint8_t channel); public: From 609959dfcee22dd0f13dace15d594cf4bdb7a683 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Fri, 17 Apr 2026 18:35:16 +0200 Subject: [PATCH 13/15] Remove comment for multiple measurements --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index 069f386e21f..3198c1a74c3 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -261,10 +261,6 @@ bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) LOG_DEBUG("Got %s readings: temperature=%.2f", sensorName, measurement->variant.environment_metrics.temperature); } - // measurement->variant.environment_metrics.one_wire_temperature[channel] = - // ds2482800Data.ds248xData[channel].temperature; - // LOG_DEBUG("Got %s readings: temperature_ch%u=%.2f", sensorName, channel, - // measurement->variant.environment_metrics.one_wire_temperature[channel]); } } return readChannel0; From aa57dae637108cd3b58ae04b0bfb0c27f537533b Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Fri, 17 Apr 2026 18:36:29 +0200 Subject: [PATCH 14/15] Add multi-sensor measurements for one-wire sensors using wildcard message --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index 3198c1a74c3..64afb825946 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -261,6 +261,13 @@ bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) LOG_DEBUG("Got %s readings: temperature=%.2f", sensorName, measurement->variant.environment_metrics.temperature); } + measurement->variant.environment_metrics.has_multi_measurement = true; + measurement->variant.environment_metrics.multi_measurement.sensor_type = meshtastic_TelemetrySensorType_DS248X; + + measurement->variant.environment_metrics.multi_measurement.measurement[channel] = + ds2482800Data.ds248xData[channel].temperature; + LOG_DEBUG("Got %s readings: temperature_ch%u=%.2f", sensorName, channel, + measurement->variant.environment_metrics.multi_measurement.measurement[channel]); } } return readChannel0; From b863c9f72433dfab177565163290a1d59b3c8621 Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Sun, 19 Apr 2026 16:32:40 +0200 Subject: [PATCH 15/15] Move to unpacked measurements in one-wire --- src/modules/Telemetry/Sensor/DS248XSensor.cpp | 68 ++++++++++++++----- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp index 64afb825946..79d4e440438 100644 --- a/src/modules/Telemetry/Sensor/DS248XSensor.cpp +++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp @@ -248,29 +248,65 @@ bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement) return true; } } else if (_variant == ds248x_variant_t::DS248X_DS2482_800) { - // If using DS248X_DS2482_800, we read all channels, but we will only report ch0 - bool readChannel0 = false; + // 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)) { - // TODO Support more than one temperature via repeated (3.0) - // TODO Select which channel can be reported as main temperature - if (channel == 0) { - readChannel0 = true; - 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); + channelCount += 1; + + 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; } - measurement->variant.environment_metrics.has_multi_measurement = true; - measurement->variant.environment_metrics.multi_measurement.sensor_type = meshtastic_TelemetrySensorType_DS248X; - measurement->variant.environment_metrics.multi_measurement.measurement[channel] = - ds2482800Data.ds248xData[channel].temperature; LOG_DEBUG("Got %s readings: temperature_ch%u=%.2f", sensorName, channel, - measurement->variant.environment_metrics.multi_measurement.measurement[channel]); + ds2482800Data.ds248xData[channel].temperature); } } - return readChannel0; + return channelCount > 0; } return false; }