Multi one wire measurements (#10192)

* 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 <tgoettgens@gmail.com>
This commit is contained in:
oscgonfer
2026-08-11 16:28:40 +00:00
committed by GitHub
co-authored by Thomas Göttgens
parent 5d04f86af3
commit cb557d89a6
4 files changed
+122 -13

No files matched your search

+11 -1
View File
@@ -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]
-1
View File
@@ -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;
+106 -11
View File
@@ -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
@@ -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