Skip to content

Commit

Permalink
add support for ams5915 and ams6915 temerature and pressure sensors (#…
Browse files Browse the repository at this point in the history
…20814)

* add support for ams5915 and ams6915 temerature and pressure sensors

* improved function namings

* optimized detection of sensor

* set verbosity level to debug

* minor code cleanings

* added seconds-counter to minimize i2c bus load, minor code cleanups

* add meas_valid in sensor struct to differentiate between sensor present (at tasmota boot) and measurement valid (if sensor was reattached) at runtime

* removed global struct and sensor_present, introduced dynamic memory allocation if sensor is present at startup, minor code changes

* fixes missing initialisation of variable

* corrected the amount of used memory if compiled with AMSX915 support

* Update my_user_config.h

disable AMSx915 by default

---------

Co-authored-by: baschdello <urschelb@rhrk.uni-kl.de>
Co-authored-by: Bastian <bastianurschel@gmail.com>
  • Loading branch information
3 people committed Feb 26, 2024
1 parent 8f1cb34 commit bf91af0
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 0 deletions.
2 changes: 2 additions & 0 deletions I2CDEVICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,7 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip
83 | USE_MAX17043 | xsns_110 | MAX17043 | 0x36 | | Fuel-gauge for 3.7 Volt Lipo battery
84 | USE_ENS16x | xsns_111 | ENS16x | 0x52 - 0x53 | | Gas (TVOC, eCO2) and air quality sensor
85 | USE_ENS210 | xsns_112 | ENS210 | 0x43 - 0x44 | | Temperature and humidity sensor
86 | USE_AMSX915 | xsns_114 | AMS5915 | 0x28 | | Pressure (absolute/differential) and temperature sensor
86 | USE_AMSX915 | xsns_114 | AMS6915 | 0x28 | | Pressure (absolute/differential) and temperature sensor

NOTE: Bus2 supported on ESP32 only.
1 change: 1 addition & 0 deletions tasmota/my_user_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@
// #define DS3231_ENABLE_TEMP // In DS3231 driver, enable the internal temperature sensor
// #define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - found in M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2.5k code)
// #define USE_PCF85363 // [I2cDriver66] Enable PCF85363 RTC - found Shelly 3EM (I2C address 0x51) (+0k7 code)
// #define USE_AMSX915 // [I2CDriver86] Enable AMS5915/AMS6915 pressure/temperature sensor (+1k2 code)

// #define USE_DISPLAY // Add I2C/TM1637/MAX7219 Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
Expand Down
240 changes: 240 additions & 0 deletions tasmota/tasmota_xsns_sensor/xsns_114_amsx915.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
/*
xsns_114_ams.ino - AMS5915, AMS6915 pressure and temperature sensor support for Tasmota
Copyright (C) 2023 Bastian Urschel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifdef USE_I2C
#ifdef USE_AMSX915
/*********************************************************************************************\
* AMS5915, AMS6915 - Pressure and Temperature
*
* Source: Bastian Urschel
*
* I2C Address: 0x28
\*********************************************************************************************/

#define XSNS_114 114
#define XI2C_86 86 // See I2CDEVICES.md

#ifndef AMSX915_ADDR
#define AMSX915_ADDR 0x28
#endif

#define AMSX915_EVERYNSECONDS 5
#define AMSX915_DEVICE_NAME "AMSx915"
#define AMSX915_LOG "AMS"

#define PMIN_DEFAULT 0
#define PMAX_DEFAULT 0

#ifndef USE_UFILESYS
#warning "AMSx915 pressure settings cannot be saved persistent due to missing filesystem"
#endif

/********************************************************************************************/

typedef struct amsx915data_s {
uint32_t file_crc32; // To detect file changes
uint16_t file_version; // To detect driver function changes
int16_t pmin;
int16_t pmax;
float pressure;
float temperature;
bool sensor_present;
bool meas_valid;
uint8_t cnt;
} amsx915data_t;
amsx915data_t *amsx915 = nullptr;

const uint16_t AMSX915_VERSION = 0x0100; // Latest sensor version (See settings deltas below)

bool Amsx915Command() {
int32_t vals[2];
ParseParameters(2,(uint32_t *)vals);
if(XdrvMailbox.data_len >= 3 && XdrvMailbox.data_len < 13) {
if (vals[0] >= -32768 && vals[0] < 32768) {
if (vals[1] >= -32768 && vals[1] < 32768) {
amsx915->pmin = (int16_t)vals[0]; // save pmin of sensor
amsx915->pmax = (int16_t)vals[1]; // same with pmax
Amsx915SettingsSave();
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_114, "pressure range set");
return true;
}
}
}
else if(XdrvMailbox.data_len == 0) {
Response_P(PSTR("{\"" AMSX915_DEVICE_NAME "\": {\"pmin\":%i,\"pmax\":%i}}"), amsx915->pmin, amsx915->pmax);
return true;
}
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_114, "invalid pressure range [-32768..32767]");
return false;
}

void Amsx915Detect(void) {
// i2c frontend does not provide any commands/register to detect this sensor type -> request 4 bytes and check for 4 byte response is mandatory

if (!I2cActive(AMSX915_ADDR))
{
uint8_t i=0;
while(i++ < 2) { // try 2 times because sensor sometimes not respond at first request
Wire.requestFrom(AMSX915_ADDR, 4);
if(Wire.available() == 4) {
I2cSetActiveFound(AMSX915_ADDR, AMSX915_DEVICE_NAME);
amsx915 = (amsx915data_t *)calloc(1, sizeof(amsx915data_t));
if (!amsx915) {
AddLog(LOG_LEVEL_ERROR, PSTR(AMSX915_LOG ":@%02X Memory error!"), AMSX915_ADDR);
}
else {
Amsx915SettingsLoad(0); // load config
}
break;
}
}
}
}

void Amsx915ReadData(void) {
if(amsx915->cnt++ == AMSX915_EVERYNSECONDS) { // try to read sensor every n seconds
amsx915->cnt = 0;
uint8_t buffer[4];
Wire.requestFrom(AMSX915_ADDR, 4);
if(Wire.available() != 4) {
amsx915->meas_valid = false;
return;
}
buffer[0] = Wire.read();
buffer[1] = Wire.read();
buffer[2] = Wire.read();
buffer[3] = Wire.read();

amsx915->pressure = ((256*(buffer[0]&0x3F)+buffer[1])-1638.0f)*((amsx915->pmax)-(amsx915->pmin))/13107+(amsx915->pmin);
amsx915->temperature = (((256.0*buffer[2]+buffer[3])*200.0f)/65536)-50;
amsx915->meas_valid = true;
}
}

void Amsx915Show(bool json) {
if(amsx915->meas_valid) {
if (json) {
ResponseAppend_P(PSTR(",\"" AMSX915_DEVICE_NAME "\":{\"" D_JSON_TEMPERATURE "\":%1_f,\"" D_JSON_PRESSURE "\":%2_f}"), &amsx915->temperature, &amsx915->pressure);
#ifdef USE_WEBSERVER
} else {
char str_pressure[9];
dtostrfd(amsx915->pressure, 2, str_pressure);
WSContentSend_PD(HTTP_SNS_PRESSURE, AMSX915_DEVICE_NAME, str_pressure, PressureUnit().c_str());
WSContentSend_Temp(AMSX915_DEVICE_NAME, amsx915->temperature);
#endif // USE_WEBSERVER
}
}
}

/*********************************************************************************************\
* Driver Settings load and save
\*********************************************************************************************/

void Amsx915SettingsLoad(bool erase) {
// Called from FUNC_PRE_INIT (erase = 0) once at restart
memset(amsx915, 0x00, sizeof(amsx915data_t));
amsx915->file_version = AMSX915_VERSION;
amsx915->pmax = PMAX_DEFAULT;
amsx915->pmin = PMIN_DEFAULT;

// *** End Init default values ***

#ifndef USE_UFILESYS
AddLog(LOG_LEVEL_INFO, PSTR("CFG: " AMSX915_DEVICE_NAME " defaults as file system not enabled"));
#else
// Try to load sensor config file
char filename[20];
snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_114);

if (erase) {
TfsDeleteFile(filename); // Use defaults
}
else if (TfsLoadFile(filename, (uint8_t*)amsx915, sizeof(amsx915data_t))) {
if (amsx915->file_version != AMSX915_VERSION) { // Fix version dependent changes
// Set current version and save settings
amsx915->file_version = AMSX915_VERSION;
Amsx915SettingsSave();
}
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: " AMSX915_DEVICE_NAME " config loaded from file"));
}
else {
// File system not ready: No flash space reserved for file system
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: " AMSX915_DEVICE_NAME " use defaults as file system not ready or file not found"));
}
#endif // USE_UFILESYS
}

void Amsx915SettingsSave(void) {
// Called from FUNC_SAVE_SETTINGS every SaveData second and at restart
#ifdef USE_UFILESYS
uint32_t crc32 = GetCfgCrc32((uint8_t*)amsx915 +4, sizeof(amsx915data_t) -4); // Skip crc32
if (crc32 != amsx915->file_crc32) {
// Try to save sensor config file
amsx915->file_crc32 = crc32;

char filename[20];
snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_114);

if (TfsSaveFile(filename, (const uint8_t*)amsx915, sizeof(amsx915data_t))) {
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: " AMSX915_DEVICE_NAME " Settings saved to file"));
} else {
// File system not ready: No flash space reserved for file system
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: ERROR " AMSX915_DEVICE_NAME " file system not ready or unable to save file"));
}
}
#endif // USE_UFILESYS
}

/*********************************************************************************************\
* Interface
\*********************************************************************************************/

bool Xsns114(uint32_t function) {
if (!I2cEnabled(XI2C_86)) { return false; }

bool result = false;

if (function == FUNC_INIT) {
Amsx915Detect();
}
if(amsx915) {
switch(function) {
case FUNC_EVERY_SECOND:
Amsx915ReadData();
break;
case FUNC_COMMAND_SENSOR:
if(XSNS_114 == XdrvMailbox.index) {
result = Amsx915Command();
}
break;
case FUNC_JSON_APPEND:
Amsx915Show(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
Amsx915Show(0);
break;
#endif // USE_WEBSERVER
}
}
return result;
}

#endif // USE_AMSX915
#endif // USE_I2C

0 comments on commit bf91af0

Please sign in to comment.