diff --git a/platformio.ini b/platformio.ini
index 46170fe0981..9cec5613fce 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -229,7 +229,9 @@ lib_deps =
https://github.com/Sensirion/arduino-i2c-scd30/archive/refs/tags/1.0.0.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
+
; Environmental sensors with BSEC2 (Bosch proprietary IAQ)
[environmental_extra]
lib_deps =
diff --git a/src/configuration.h b/src/configuration.h
index 84dabee4e83..963686b3d93 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -271,6 +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 // 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/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..ac54fcc5474 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);
@@ -478,7 +487,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 +500,14 @@ 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 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("DS248X", (uint8_t)addr.address);
}
break;
}
@@ -536,7 +552,27 @@ 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;
+ }
+ 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
@@ -562,7 +598,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
@@ -573,10 +619,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:
@@ -624,11 +680,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/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
}
diff --git a/src/modules/Telemetry/Sensor/DS248XSensor.cpp b/src/modules/Telemetry/Sensor/DS248XSensor.cpp
new file mode 100644
index 00000000000..79d4e440438
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/DS248XSensor.cpp
@@ -0,0 +1,314 @@
+#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(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]);
+}
+
+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 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;
+ uint8_t nROMDetected = 0;
+
+ if (detectVariant() == DS248X_DS2482_800) {
+
+ LOG_INFO("%s: Multi-channel DS2482-800 detected", sensorName);
+
+ for (uint8_t channel = 0; channel < 8; channel++) {
+
+ if (ds248x.selectChannel(channel)) {
+
+ ds248x.OneWireReset();
+
+ if (!ds248x.OneWireSearch(ds2482800Data.ds248xData[channel].rom)) {
+ 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;
+ }
+ } 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;
+ }
+
+ } 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) {
+#if defined(DS248X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
+ reClockI2C(currentClock, _bus, false);
+#endif
+ LOG_ERROR("%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;
+ // 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);
+ }
+
+ initI2CSensor();
+ return status;
+}
+
+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(const 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 -1000.0;
+#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;
+
+ return celsius;
+}
+
+bool DS248XSensor::readTemperatureChannel(uint8_t channel)
+{
+ if (!isValidROM(ds2482800Data.ds248xData[channel].rom)) {
+ LOG_DEBUG("%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
+ LOG_WARN("%s: Failed to select channel %u", sensorName, channel);
+ return false;
+ }
+
+ float temperature;
+ temperature = readTemperatureROM(ds2482800Data.ds248xData[channel].rom);
+
+ if (temperature != -1000.0) {
+ ds2482800Data.ds248xData[channel].temperature = temperature;
+ LOG_DEBUG("%s: read temperature in channel %u: %0.2f", sensorName, channel, temperature);
+ }
+ return true;
+}
+
+bool DS248XSensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ if (_variant == ds248x_variant_t::DS248X_DS2484) {
+ 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;
+ }
+ } else if (_variant == ds248x_variant_t::DS248X_DS2482_800) {
+ // 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;
+
+ 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 channelCount > 0;
+ }
+ 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..54924fef526
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/DS248XSensor.h
@@ -0,0 +1,77 @@
+#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
+
+#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
+#endif
+
+#ifndef DS18B20_CMD_MATCH_ROM
+#define DS18B20_CMD_MATCH_ROM 0x55
+#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;
+
+struct _DS248XData {
+ uint8_t rom[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ 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(const uint8_t *rom);
+ bool isValidROM(const uint8_t *rom);
+ float readTemperatureROM(const 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