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
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ build_flags =
-D ENV_INCLUDE_VL53L0X=1
-D ENV_INCLUDE_BME680=1
-D ENV_INCLUDE_BMP085=1
-D ENV_INCLUDE_OPT3001=1
lib_deps =
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
Expand Down
30 changes: 30 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_OPT3001
#ifndef TELEM_OPT3001_ADDRESS
#define TELEM_OPT3001_ADDRESS 0x44 // OPT3001 ambient light sensor (RAK1903) I2C address
#endif
#include "OPT3001.h"
static OPT3001 OPT3001;
#endif

#if ENV_INCLUDE_GPS && defined(RAK_BOARD) && !defined(RAK_WISMESH_TAG)
#define RAK_WISBLOCK_GPS
#endif
Expand Down Expand Up @@ -401,6 +409,7 @@ static void query_ina260(uint8_t ch, uint8_t, CayenneLPP& lpp) {
static uint8_t init_ina226(TwoWire*, uint8_t) {
// INA226 static instance was constructed with address and wire.
if (!INA226.begin()) return 0;
if (INA226.getManufacturerID() != 0x5449 || INA226.getDieID() != 0x2260) return 0;
INA226.setMaxCurrentShunt(TELEM_INA226_MAX_AMP, TELEM_INA226_SHUNT_VALUE);
return 1;
}
Expand Down Expand Up @@ -531,6 +540,24 @@ static void query_bme680_bsec(uint8_t ch, uint8_t, CayenneLPP& lpp) {
}
#endif

#if ENV_INCLUDE_OPT3001
static uint8_t init_opt3001(TwoWire* wire, uint8_t addr) {
// probe() is read-only. 0x44 may also be an SHT4X or INA226,
// so chip is identified by manufacturer/device ID before any
// config is written.
if(!OPT3001.probe(wire, addr)) return 0;
return OPT3001.begin() ? 1 : 0;
}

static void query_opt3001(uint8_t ch, uint8_t, CayenneLPP& lpp) {
float lux;
if (OPT3001.readLux(lux)) {
lpp.addLuminosity(ch, lux);
}
}

#endif

// ============================================================
// Sensor descriptor table
//
Expand Down Expand Up @@ -599,6 +626,9 @@ static const SensorDef SENSOR_TABLE[] = {
#endif
#if ENV_INCLUDE_RAK12035
{ TELEM_RAK12035_ADDRESS,"RAK12035", init_rak12035, query_rak12035 },
#endif
#if ENV_INCLUDE_OPT3001
{ TELEM_OPT3001_ADDRESS,"OPT3001", init_opt3001, query_opt3001 },
#endif
{ 0, nullptr, nullptr, nullptr } // sentinel — keeps the array non-empty
};
Expand Down
56 changes: 56 additions & 0 deletions src/helpers/sensors/OPT3001.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "OPT3001.h"

bool OPT3001::readReg(uint8_t reg, uint16_t& value) {
_wire->beginTransmission(_addr);
_wire->write(reg);
if (_wire->endTransmission() != 0) return false;

if (_wire->requestFrom(_addr, (uint8_t)2) != 2) return false;
uint16_t msb = _wire->read(); // sequence the two reads
uint16_t lsb = _wire->read();
value = (msb << 8) | lsb;
return true;
}

bool OPT3001::writeReg(uint8_t reg, uint16_t value) {
_wire->beginTransmission(_addr);
_wire->write(reg);
_wire->write((uint8_t)(value >> 8));
_wire->write((uint8_t)(value & 0xFF));
return _wire->endTransmission() == 0;
}

bool OPT3001::probe(TwoWire* wire, uint8_t addr) {
_wire = wire;
_addr = addr;

uint16_t id;
if (!readReg(OPT3001_REG_MANUFACTURER_ID, id) || id != OPT3001_MANUFACTURER_ID) return false;
if (!readReg(OPT3001_REG_DEVICE_ID, id) || id != OPT3001_DEVICE_ID) return false;
return true;
}

bool OPT3001::begin() {
_ready = false;
return writeReg(OPT3001_REG_CONFIG, OPT3001_CONFIG_CONTINUOUS);
}

bool OPT3001::readLux(float& lux) {
if (!_ready) {
// Reading the latched config register clears CRF, however
// in continuous mode it is set again after every conversion.
// We only need to gate the very first read after begin().
uint16_t config;
if (!readReg(OPT3001_REG_CONFIG, config)) return false;
if ((config & OPT3001_CONFIG_CRF) == 0) return false;
_ready = true;
}

uint16_t raw;
if (!readReg(OPT3001_REG_RESULT, raw)) return false;

// Result format: exponent E in [15:12], mantissa R in [11:0]
// lux = 0.01 * 2^E * R (full-scale 83865.6 lux)
lux = 0.01f * (float)(1u << (raw >> 12)) * (float)(raw & 0x0FFF);
return true;
}
52 changes: 52 additions & 0 deletions src/helpers/sensors/OPT3001.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* @file OPT3001.h
* @author Nick Dunklee
* @brief Minimal driver for the TI OPT3001 ambient light sensor
* (used on the RAK1903 WisBlock module).
*
* Written for MeshCore from the TI OPT3001 datasheet (SBOS681).
* https://www.ti.com/lit/ds/sbos681b/sbos681b.pdf
*
* The default address of 0x44 is shared with other sensors (SHT4x,
* INA226), so probe() performs a read-only identity check and no
* register is written until the chip is positively ID'd.
*/

#pragma once

#include <Arduino.h>
#include <Wire.h>

#define OPT3001_REG_RESULT 0x00
#define OPT3001_REG_CONFIG 0x01
#define OPT3001_REG_MANUFACTURER_ID 0x7E
#define OPT3001_REG_DEVICE_ID 0x7F

#define OPT3001_MANUFACTURER_ID 0x5449 // TI
#define OPT3001_DEVICE_ID 0x3001

// Automatic full-scale range, 800ms conversions, continuous mode, latched flags
#define OPT3001_CONFIG_CONTINUOUS 0xCE10
#define OPT3001_CONFIG_CRF 0x0080 // conversion ready flag

class OPT3001 {
TwoWire* _wire;
uint8_t _addr;
bool _ready; // at least one conversion has completed since begin()

bool readReg(uint8_t reg, uint16_t& value);
bool writeReg(uint8_t reg, uint16_t value);

public:
OPT3001() : _wire(NULL), _addr(0), _ready(false) { }

// Read-only identity check (manufacturer + device ID). Safe to call
// on a foreign device that happens to share the I2C address.
bool probe(TwoWire* wire, uint8_t addr);

// Start continuous conversions. Call only after probe() succeeds.
bool begin();

// Return false until the first conversion completes.
bool readLux(float& lux);
};
1 change: 1 addition & 0 deletions variants/lilygo_tdeck/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ build_flags =
-D ENV_INCLUDE_VL53L0X=0
-D ENV_INCLUDE_BME680=0
-D ENV_INCLUDE_BMP085=0
-D ENV_INCLUDE_OPT3001=0
-D P_LORA_NSS=9 ; LORA SS pin
-D P_LORA_RESET=17 ; LORA RST pin
-D P_LORA_BUSY=13 ; LORA Busy pin
Expand Down