-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add support for ams5915 and ams6915 temerature and pressure sensors (#…
…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
1 parent
8f1cb34
commit bf91af0
Showing
3 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |