Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ lib_deps =
stevemarple/MicroNMEA @ ^2.0.6
adafruit/Adafruit BME680 Library @ ^2.0.4
adafruit/Adafruit BMP085 Library @ ^1.2.4
paulstoffregen/OneWire @ ^2.3.8
milesburton/DallasTemperature @ ^3.11.0

; ----------------- TESTING ---------------------

Expand Down
46 changes: 46 additions & 0 deletions src/helpers/sensors/EnvironmentSensorManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ static Adafruit_VL53L0X VL53L0X;
static RAK12035_SoilMoisture RAK12035;
#endif

#if ENV_INCLUDE_ONEWIRE
#ifndef TELEM_ONEWIRE_PIN
#error "ENV_INCLUDE_ONEWIRE requires TELEM_ONEWIRE_PIN to be defined in the board's build_flags"
#endif
#include "OneWireSensor.h"
static OneWireSensor ONEWIRE(TELEM_ONEWIRE_PIN);
#endif

#if ENV_INCLUDE_GPS && defined(RAK_BOARD) && !defined(RAK_WISMESH_TAG)
#define RAK_WISBLOCK_GPS
#endif
Expand Down Expand Up @@ -475,6 +483,16 @@ static void query_rak12035(uint8_t ch, uint8_t sub_ch, CayenneLPP& lpp) {
}
#endif

#if ENV_INCLUDE_ONEWIRE
// 1-Wire has no I2C address and no init(wire, addr) entry — its
// presence-pulse probe and bus enumeration both live in
// OneWireSensor::begin(), called from the dedicated registration
// pass in EnvironmentSensorManager::begin().
static void query_onewire(uint8_t ch, uint8_t sub_ch, CayenneLPP& lpp) {
ONEWIRE.query(ch, sub_ch, lpp);
}
#endif

#if ENV_INCLUDE_BME680_BSEC
static void bsec_load_state() {
using namespace Adafruit_LittleFS_Namespace;
Expand Down Expand Up @@ -655,6 +673,34 @@ bool EnvironmentSensorManager::begin() {
}
}

// ----------------------------------------------------------
// 1-Wire bus registration pass.
//
// Portability: any board enables 1-Wire by adding
// -D ENV_INCLUDE_ONEWIRE=1
// -D TELEM_ONEWIRE_PIN=<gpio>
// to its variant's build_flags. No source changes required.
//
// OneWireSensor::begin() issues a 1-Wire reset and checks for a
// presence pulse before touching DallasTemperature, mirroring the
// I2C ACK gate above. With no probe attached, it returns 0 and no
// entries are pushed — the same "never touch absent hardware"
// invariant applies here as on the I2C bus.
// ----------------------------------------------------------
#if ENV_INCLUDE_ONEWIRE
{
uint8_t found = ONEWIRE.begin();
if (found == 0) {
MESH_DEBUG_PRINTLN("1-Wire not detected on pin %d", (int)TELEM_ONEWIRE_PIN);
} else {
MESH_DEBUG_PRINTLN("Found %u 1-Wire temperature device(s) on pin %d", (unsigned)found, (int)TELEM_ONEWIRE_PIN);
for (uint8_t sub = 0; sub < found && _active_sensor_count < MAX_ACTIVE_SENSORS; sub++) {
_active_sensors[_active_sensor_count++] = { query_onewire, sub };
}
}
}
#endif

return true;
}

Expand Down
68 changes: 68 additions & 0 deletions src/helpers/sensors/OneWireSensor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include "OneWireSensor.h"

#if ENV_INCLUDE_ONEWIRE

// 1-Wire ROM family codes for the temperature devices the
// DallasTemperature library knows how to decode. Centralised here so
// the family filter in begin() reads as a list of supported parts.
static inline bool is_temperature_family(uint8_t family) {
switch (family) {
case 0x10: // DS18S20 / DS1820
case 0x22: // DS1822
case 0x28: // DS18B20
case 0x3B: // DS1825 / MAX31850
case 0x42: // DS28EA00
return true;
default:
return false;
}
}

OneWireSensor::OneWireSensor(uint8_t pin)
: _bus(pin), _dallas(&_bus) {}

uint8_t OneWireSensor::begin() {
// Presence-pulse gate. OneWire::reset() returns 1 only when at
// least one device on the bus pulls the line low in response to
// the reset pulse. Without it, we skip DallasTemperature entirely.
if (_bus.reset() != 1) return 0;

_dallas.begin();

const uint8_t bus_total = _dallas.getDeviceCount();
_count = 0;
for (uint8_t i = 0; i < bus_total && _count < MAX_DEVICES; i++) {
DeviceAddress addr;
if (!_dallas.getAddress(addr, i)) continue;

// Extension point: a future non-temperature family (e.g. DS2438
// battery monitor, family 0x26) would dispatch on this family
// byte to its own driver and register a different query_* free
// function from the manager. The presence-pulse gate above and
// the per-device address storage below are family-agnostic and
// can be reused as-is.
if (!is_temperature_family(addr[0])) continue;

memcpy(_addresses[_count], addr, sizeof(DeviceAddress));
_count++;
}

return _count;
}

void OneWireSensor::query(uint8_t channel, uint8_t index, CayenneLPP& lpp) {
if (index >= _count) return;

// Per-device blocking conversion keeps query() stateless and
// independent of call order — the cost is one conversion window
// (~750 ms at default 12-bit resolution) per device per cycle,
// which matches the synchronous read pattern used by the other
// sensors in EnvironmentSensorManager.
_dallas.requestTemperaturesByAddress(_addresses[index]);
const float t = _dallas.getTempC(_addresses[index]);
if (t == DEVICE_DISCONNECTED_C) return;

lpp.addTemperature(channel, t);
}

#endif // ENV_INCLUDE_ONEWIRE
50 changes: 50 additions & 0 deletions src/helpers/sensors/OneWireSensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

// Standalone 1-Wire bus driver for EnvironmentSensorManager.
//
// Covers every DallasTemperature-supported temperature family on one
// bus pin: DS18B20 (0x28), DS18S20 (0x10), DS1822 (0x22), DS1825 /
// MAX31850 (0x3B), DS28EA00 (0x42). Each detected device is exposed
// as its own telemetry sub-channel, so an air-and-water deployment
// with two probes on the same pin "just works".
//
// Portability contract: this file contains no board-specific pins or
// #ifdefs. The bus pin comes from the per-board build flag
// TELEM_ONEWIRE_PIN, and the whole module is compiled out when
// ENV_INCLUDE_ONEWIRE is not set.

#if ENV_INCLUDE_ONEWIRE

#include <Arduino.h>
#include <CayenneLPP.h>
#include <OneWire.h>
#include <DallasTemperature.h>

class OneWireSensor {
public:
// Upper bound on devices enumerated from a single bus. Kept under
// EnvironmentSensorManager::MAX_ACTIVE_SENSORS so a fully populated
// bus cannot overflow the active-sensor table on its own.
static const uint8_t MAX_DEVICES = 8;

explicit OneWireSensor(uint8_t pin);

// Probes the bus for a 1-Wire presence pulse — the direct analog of
// the I2C ACK check the manager's address scan relies on. With no
// pulse, returns 0 and DallasTemperature is never engaged; this
// preserves the manager's "never touch absent hardware" invariant.
// Otherwise enumerates the bus and returns the number of detected
// temperature-family devices (clamped to MAX_DEVICES).
uint8_t begin();

// Reads device `index` and writes one temperature channel.
void query(uint8_t channel, uint8_t index, CayenneLPP& lpp);

private:
OneWire _bus;
DallasTemperature _dallas;
uint8_t _count = 0;
DeviceAddress _addresses[MAX_DEVICES];
};

#endif // ENV_INCLUDE_ONEWIRE
2 changes: 2 additions & 0 deletions variants/rak4631/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ build_flags =
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ENV_INCLUDE_ONEWIRE=1
-D TELEM_ONEWIRE_PIN=WB_IO1
; -D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
Expand Down