Skip to content

Commit

Permalink
[P177] Add plugin Environment - XDB401 I2C Pressure
Browse files Browse the repository at this point in the history
  • Loading branch information
tonhuisman committed Feb 22, 2025
1 parent 6260306 commit 398ed46
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 1 deletion.
128 changes: 128 additions & 0 deletions src/_P177_XDB_pressure.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include "_Plugin_Helper.h"
#ifdef USES_P177

// #######################################################################################################
// ################################ Plugin 177 XDB401 I2C Pressure Sensor ################################
// #######################################################################################################

/** Changelog:
* 2025-02-22 tonhuisman: Initial plugin development, direct I2C access,
* based on this documentation: https://www.letscontrolit.com/forum/viewtopic.php?t=10568#p71993 (attachment)
*/

# define PLUGIN_177
# define PLUGIN_ID_177 177
# define PLUGIN_NAME_177 "Environment - XDB401 I2C Pressure"
# define PLUGIN_VALUENAME1_177 "Pressure"
# define PLUGIN_VALUENAME2_177 "Temperature"

# include "./src/PluginStructs/P177_data_struct.h"

boolean Plugin_177(uint8_t function, struct EventStruct *event, String& string)
{
boolean success = false;

switch (function)
{
case PLUGIN_DEVICE_ADD:
{
auto& dev = Device[++deviceCount];
dev.Number = PLUGIN_ID_177;
dev.Type = DEVICE_TYPE_I2C;
dev.VType = Sensor_VType::SENSOR_TYPE_DUAL;
dev.FormulaOption = true;
dev.ValueCount = 2;
dev.SendDataOption = true;
dev.TimerOption = true;
dev.TimerOptional = true;
dev.PluginStats = true;
break;
}

case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_177);
break;
}

case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_177));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_177));
break;
}

case PLUGIN_I2C_HAS_ADDRESS:
{
success = P177_I2C_ADDR == event->Par1;
break;
}

# if FEATURE_I2C_GET_ADDRESS
case PLUGIN_I2C_GET_ADDRESS:
{
event->Par1 = P177_I2C_ADDR;
success = true;
break;
}
# endif // if FEATURE_I2C_GET_ADDRESS

case PLUGIN_SET_DEFAULTS:
{
P177_PRESSURE_SCALE_FACTOR = 1; // Default to 1
break;
}

case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(F("Pressure scaling factor"), F("scale"), P177_PRESSURE_SCALE_FACTOR, 1);

addFormNumericBox(F("Temperature offset"), F("tempoffset"), P177_TEMPERATURE_OFFSET);
addUnit(F("x 0.1C"));
addFormNote(F("Offset in units of 0.1 degree Celsius"));

success = true;
break;
}

case PLUGIN_WEBFORM_SAVE:
{
P177_PRESSURE_SCALE_FACTOR = getFormItemInt(F("scale"), 1000);
P177_TEMPERATURE_OFFSET = getFormItemInt(F("tempoffset"), 0);

success = true;
break;
}

case PLUGIN_INIT:
{
success = initPluginTaskData(event->TaskIndex, new (std::nothrow) P177_data_struct());
break;
}

case PLUGIN_READ:
{
P177_data_struct *P177_data = static_cast<P177_data_struct *>(getPluginTaskData(event->TaskIndex));

if (nullptr != P177_data) {
success = P177_data->plugin_read(event);
}

break;
}

case PLUGIN_TEN_PER_SECOND:
{
P177_data_struct *P177_data = static_cast<P177_data_struct *>(getPluginTaskData(event->TaskIndex));

if (nullptr != P177_data) {
success = P177_data->plugin_ten_per_second(event);
}

break;
}
}
return success;
}

#endif // ifdef USES_P177
9 changes: 9 additions & 0 deletions src/src/CustomBuild/define_plugin_sets.h
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,9 @@ To create/register a plugin, you have to :
#if !defined(USES_P173) && defined(ESP32)
#define USES_P173 // Environment - SHTC3
#endif
#if !defined(USES_P177) && defined(ESP32)
#define USES_P177 // Environment - I2C XDB401 pressure
#endif
#if !defined(USES_P178) && defined(ESP32)
#define USES_P178 // Extra IO - LU9685 Servo controller
#endif
Expand Down Expand Up @@ -2041,6 +2044,9 @@ To create/register a plugin, you have to :
#if !defined(USES_P175) && defined(ESP32)
#define USES_P175 // Dust - PMSx003i I2C
#endif
#if !defined(USES_P177) && defined(ESP32)
#define USES_P177 // Environment - I2C XDB401 pressure
#endif
#if !defined(USES_P178) && defined(ESP32)
#define USES_P178 // Extra IO - LU9685 Servo controller
#endif
Expand Down Expand Up @@ -2524,6 +2530,9 @@ To create/register a plugin, you have to :
#ifndef USES_P175
#define USES_P175 // Dust - PMSx003i I2C
#endif
#ifndef USES_P177
#define USES_P177 // Environment - I2C XDB401 pressure
#endif
#ifndef USES_P178
#define USES_P178 // Extra IO - LU9685 Servo controller
#endif
Expand Down
115 changes: 115 additions & 0 deletions src/src/PluginStructs/P177_data_struct.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "../PluginStructs/P177_data_struct.h"

#ifdef USES_P177


P177_data_struct::~P177_data_struct() {}

bool P177_data_struct::plugin_ten_per_second(struct EventStruct *event) {
bool is_ok;
uint8_t byteData;

if (P177_SensorMode_e::IdleMode == _sensorMode) {
_cycles--;

if (_cycles) { // Skip until counted down to 0
return false;
}
byteData = I2C_read8_reg(P177_I2C_ADDR, P177_COMMAND_REG, &is_ok);

if (is_ok && (0 == bitRead(byteData, 3))) { // Not currently reading
I2C_write8_reg(P177_I2C_ADDR, P177_COMMAND_REG, P177_START_READ);
_sensorMode = P177_SensorMode_e::SensingMode;
_cycles = P177_SKIP_CYCLES; // Restart timer after a read is started
}
return false;
}

if (P177_SensorMode_e::SensingMode == _sensorMode) {
byteData = I2C_read8_reg(P177_I2C_ADDR, P177_COMMAND_REG, &is_ok);

if (!is_ok || (1 == bitRead(byteData, 3))) { // Currently reading
return false;
}
_sensorMode = P177_SensorMode_e::ReportingMode;
}

uint32_t prData;
uint16_t tmData;

# if P177_LOG
String log = F("P177 : RAW data: ");
# endif // if P177_LOG
size_t i = 0;

for (; i < 3; ++i) { // first 3 bytes pressure
prData << 8;
byteData = I2C_read8_reg(P177_I2C_ADDR, P177_DATA_REG_1 + i);
prData |= byteData;
# if P177_LOG
log += strformat(F("0x%02X "), byteData);
# endif // if P177_LOG
}
# if P177_LOG
log += strformat(F("prData: 0x%06X, "), prData);
# endif // if P177_LOG

for (; i < P177_DATA_BYTES; ++i) { // 2 more bytes temperature
tmData << 8;
byteData = I2C_read8_reg(P177_I2C_ADDR, P177_DATA_REG_1 + i);
tmData |= byteData;
# if P177_LOG
log += strformat(F("0x%02X "), byteData);
# endif // if P177_LOG
}

# if P177_LOG
log += strformat(F(" tmData: 0x%04X"), tmData);
addLog(LOG_LEVEL_INFO, log);
# endif // if P177_LOG

_sensorMode = P177_SensorMode_e::IdleMode; // Start a new cycle

if ((prData == _rawPressure) && (tmData == _rawTemperature)) {
return false;
}
_rawPressure = prData;
_rawTemperature = tmData;
_updated = true;
return true;
}

bool P177_data_struct::plugin_read(struct EventStruct *event) {
if (!_updated) {
// Needed to get the 1st value, or can get the latest value when sampled too frequently.
plugin_ten_per_second(event);
}

if (_updated) {
float _pressure = _rawPressure;

if (_rawPressure & 0x80000) {
_pressure = -1 * (_rawPressure & 0x3FFFF);
}
_pressure /= (0x80000 / P177_PRESSURE_SCALE_FACTOR);

float _temperature = _rawTemperature;

if (_rawTemperature & 0x8000) {
_temperature = -1 * (_rawTemperature & 0x3FFF);
}
_temperature /= 256;

if (P177_TEMPERATURE_OFFSET != 0) {
_temperature += (P177_TEMPERATURE_OFFSET / 10); // In 0.1 degree steps
}

UserVar.setFloat(event->TaskIndex, 0, _pressure);
UserVar.setFloat(event->TaskIndex, 1, _temperature);
_updated = false;
return true;
}
return false;
}

#endif // ifdef USES_P177
50 changes: 50 additions & 0 deletions src/src/PluginStructs/P177_data_struct.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef PLUGINSTRUCTS_P177_DATA_STRUCT_H
#define PLUGINSTRUCTS_P177_DATA_STRUCT_H

#include "../../_Plugin_Helper.h"

#ifdef USES_P177
# include "../Helpers/I2C_access.h"

# define P177_LOG 1 // Set to 1 to enable raw data logging at INFO level

# define P177_I2C_ADDR 0x7F // Fixed address

# define P177_COMMAND_REG 0x30
# define P177_START_READ 0x0A
# define P177_DATA_REG_1 0x06
# define P177_DATA_BYTES 5

# define P177_SKIP_CYCLES 5 // Skip this number of 10/sec cycles when in IdleMode

# define P177_PRESSURE_SCALE_FACTOR PCONFIG_LONG(0) // Pressure scaling factor
# define P177_TEMPERATURE_OFFSET PCONFIG(0) // Temperature compensation in 0.1 degree steps

enum class P177_SensorMode_e : uint8_t {
IdleMode = 0u,
SensingMode = 1u,
ReportingMode = 2u,
};

/*******************************************
* P177 Plugin taskdata struct
******************************************/
struct P177_data_struct : public PluginTaskData_base {
public:

P177_data_struct() = default;
~P177_data_struct();

bool plugin_ten_per_second(struct EventStruct *event);

bool plugin_read(struct EventStruct *event);

uint32_t _rawPressure{};
uint16_t _rawTemperature{};
P177_SensorMode_e _sensorMode = P177_SensorMode_e::IdleMode;
uint8_t _cycles = 1; // Start cycle immediately
bool _updated = false;
};

#endif // ifdef USES_P177
#endif // ifndef PLUGINSTRUCTS_P177_DATA_STRUCT_H
2 changes: 1 addition & 1 deletion src/src/WebServer/I2C_Scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ String getKnownI2Cdevice(uint8_t address) {
result += F("LiquidLevel");
break;
case 0x7f:
result += F("Arduino PME");
result += F("Arduino PME,XDB401");
break;
}
#endif // LIMIT_BUILD_SIZE
Expand Down

0 comments on commit 398ed46

Please sign in to comment.