Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding driver for the Texas Instruments HDC1080 #7888

Merged
merged 18 commits into from
Mar 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7c857b0
Added the command SerialConfig with the capability of changing the da…
teixeluis Dec 4, 2019
18f5143
Merge branch 'development' of https://github.com/arendst/Tasmota into…
teixeluis Dec 4, 2019
83f9c7b
Fixed comment (bits for each field)
teixeluis Dec 4, 2019
871fd1f
Added the new text field D_SET_SERIAL_CONFIG_TO (used in the logs) to…
teixeluis Dec 5, 2019
3cf6b8b
Merge branch 'development' of https://github.com/arendst/Tasmota into…
teixeluis Mar 7, 2020
3908865
Added the hdc1080 device driver.
teixeluis Mar 8, 2020
cb2cc9b
More intermediate changes and troubleshooting.
teixeluis Mar 9, 2020
2a06a6b
Fixed issue when reading temperature and humidity in the same transac…
teixeluis Mar 10, 2020
e9d201a
Fixed issue during the call to ResponseAppend_P (was passing
teixeluis Mar 10, 2020
4910e03
Merge branch 'development' of https://github.com/arendst/Tasmota into…
teixeluis Mar 10, 2020
725b989
Added cast to properly deal with the AddLogMissed function prototype.
teixeluis Mar 10, 2020
78a608d
Synched with resources from original repo
teixeluis Mar 10, 2020
2926981
Minor correction to the description. Slightly simplified declaration …
teixeluis Mar 10, 2020
b7907ae
Merge branch 'development' of https://github.com/arendst/Tasmota into…
teixeluis Mar 12, 2020
b758699
Some corrections based on feedback from the project leads contributors.
teixeluis Mar 13, 2020
99a0061
Merge branch 'development' of https://github.com/arendst/Tasmota into…
teixeluis Mar 13, 2020
2441acd
Fixed the sensor read errors that were due to misplaced timer variabl…
teixeluis Mar 13, 2020
a5ebdd3
Update decode-status.py
arendst Mar 14, 2020
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 BUILDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
| USE_DHT12 | - | - | - | - | x | - | - |
| USE_DS1624 | - | - | - | - | x | - | - |
| USE_AHT1x | - | - | - | - | - | - | - |
| USE_HDC1080 | - | - | - | - | - | - | - |
| USE_WEMOS_MOTOR_V1 | - | - | - | - | x | - | - |
| | | | | | | | |
| Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks
Expand Down
1 change: 1 addition & 0 deletions I2CDEVICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ Index | Define | Driver | Device | Address(es) | Description
42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor
43 | USE_AHT1x | xsns_63 | AHT10/15 | 0x38 | Temperature and humidity sensor
44 | USE_WEMOS_MOTOR_V1 | xdrv_34 | | 0x2D - 0x30 | WEMOS motor shield v1.0.0 (6612FNG)
45 | USE_HDC1080 | xsns_65 | HDC1080 | 0x40 | Temperature and Humidity sensor
2 changes: 2 additions & 0 deletions tasmota/my_user_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@
// #define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) (+1k2 code)
// #define USE_AHT1x // [I2cDriver43] Enable AHT10/15 humidity and temperature sensor (I2C address 0x38) (+0k8 code)
// #define USE_WEMOS_MOTOR_V1 // [I2cDriver44] Enable Wemos motor driver V1 (I2C addresses 0x2D - 0x30) (+0k7 code)
// #define USE_HDC1080 // [I2cDriver92] Enable HDC1080 temperature/humidity sensor
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be a [I2cDriver45] ? Looks like an artifact from the first patch.


// #define WEMOS_MOTOR_V1_ADDR 0x30 // Default I2C address 0x30
// #define WEMOS_MOTOR_V1_FREQ 1000 // Default frequency

Expand Down
1 change: 0 additions & 1 deletion tasmota/support_features.ino
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,6 @@ void GetFeatures(void)
#ifdef USE_TM1638
feature_sns1 |= 0x80000000; // xsns_28_tm1638.ino
#endif

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

feature_sns2 = 0x00000000;
Expand Down
3 changes: 3 additions & 0 deletions tasmota/tasmota_post.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
#define USE_DHT12 // Add I2C code for DHT12 temperature and humidity sensor (+0k7 code)
#define USE_DS1624 // Add I2C code for DS1624, DS1621 sensor
//#define USE_AHT1x // Enable AHT10/15 humidity and temperature sensor (I2C address 0x38) (+0k8 code)
//#define USE_HDC1080 // Enable HDC1080 temperature/humidity sensor

Copy link
Owner

@arendst arendst Mar 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disable HDC for now as I need to tests it's consequences first. This also is in line with your change in BUILD.md where you rightfully disabled the sensor in all binaries.


#define USE_WEMOS_MOTOR_V1 // Enable Wemos motor driver V1 (I2C addresses 0x2D - 0x30) (+0k7 code)
#define WEMOS_MOTOR_V1_ADDR 0x30 // Default I2C address 0x30
#define WEMOS_MOTOR_V1_FREQ 1000 // Default frequency
Expand Down
349 changes: 349 additions & 0 deletions tasmota/xsns_65_hdc1080.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
/*
xsns_92_hdc1080.ino - Texas Instruments HDC1080 temperature and humidity sensor support for Tasmota

Copyright (C) 2020 Luis Teixeira

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_HDC1080

/*********************************************************************************************\
* HDC1080 - Temperature and Humidy sensor
*
* Source: Luis Teixeira
*
* I2C Address: 0x40
\*********************************************************************************************/

#define XSNS_65 65
#define XI2C_45 45 // See I2CDEVICES.md

#define HDC1080_ADDR 0x40

// Registers:

#define HDC_REG_TEMP 0x00 // Temperature register
#define HDC_REG_RH 0x01 // Humidity register
#define HDC_REG_CONFIG 0x02 // Configuration register
#define HDC_REG_SERIAL1 0xFB // First 2 bytes of the serial ID
#define HDC_REG_SERIAL2 0xFC // Mid 2 bytes of the serial ID
#define HDC_REG_SERIAL3 0xFD // Last bits of the serial ID
#define HDC_REG_MAN_ID 0xFE // Manufacturer ID
#define HDC_REG_DEV_ID 0xFF // Device ID

// Expected constant values of some of the registers:

#define HDC1080_MAN_ID 0x5449 // Manufacturer ID (Texas Instruments)
#define HDC1080_DEV_ID 0x1050 // Device ID (valid for the HDC1080)

// Possible values for the configuration register fields:

#define HDC1080_RST_ON 0x8000
#define HDC1080_HEAT_ON 0x2000
#define HDC1080_MODE_ON 0x1000 // acquision mode (temperature + humidity)
#define HDC1080_TRES_11 0x400
#define HDC1080_HRES_11 0x100
#define HDC1080_HRES_8 0x80

// Constants:

#define HDC1080_CONV_TIME 15 // Assume 6.50 + 6.35 ms + x of conversion delay for this device
#define HDC1080_TEMP_MULT 0.0025177
#define HDC1080_RH_MULT 0.0025177
#define HDC1080_TEMP_OFFSET 40.0

const char* hdc_type_name = "HDC1080";
uint16_t hdc_manufacturer_id = 0;
uint16_t hdc_device_id = 0;

float hdc_temperature = 0.0;
float hdc_humidity = 0.0;

uint8_t hdc_valid = 0;

bool is_reading = false;
uint32_t hdc_next_read;

/**
* Reads the device ID register.
*
*/
uint16_t HdcReadDeviceId(void) {
return I2cRead16(HDC1080_ADDR, HDC_REG_DEV_ID);
}

/**
* Reads the manufacturer ID register.
*
*/
uint16_t HdcReadManufacturerId(void) {
return I2cRead16(HDC1080_ADDR, HDC_REG_MAN_ID);
}

/**
* Overwrites the configuration register with the provided config
*/
void HdcConfig(uint16_t config) {
I2cWrite16(HDC1080_ADDR, HDC_REG_CONFIG, config);
}

/**
* Performs a soft reset on the device.
*
* RST = 1 -> software reset
*
*/
void HdcReset(void) {
uint16_t current = I2cRead16(HDC1080_ADDR, HDC_REG_CONFIG);

// bit 15 of the configuration register contains the RST flag
// so we set it to 1:

current |= 0x8000;

I2cWrite16(HDC1080_ADDR, HDC_REG_CONFIG, current);

delay(HDC1080_CONV_TIME); // Not sure how long it takes to reset. Assuming this value.
}

/**
* Performs the write portion of the HDC1080 sensor transaction. This
* action of writing to a register signals the beginning of the operation
* (e.g. data acquisition).
*
* addr: the address of the I2C device we are talking to.
* reg: the register where we are writing to.
*
* returns: 0 if the transmission was successfully completed, != 0 otherwise.
*/
int8_t HdcTransactionOpen(uint8_t addr, uint8_t reg) {
Wire.beginTransmission((uint8_t) addr);
Wire.write((uint8_t) reg);
return Wire.endTransmission();
}

/**
* Performs the read portion of the HDC1080 sensor transaction.
*
* addr: the address of the I2C device we are talking to.
* reg_data: the pointer to the memory location where we will place the bytes that were read from the device
* len: the number of bytes we expect to read
*
* returns: if the read operation was successful. != 0 otherwise.
*/
int8_t HdcTransactionClose(uint8_t addr, uint8_t *reg_data, uint16_t len) {
if (len != Wire.requestFrom((uint8_t) addr, (uint8_t) len)) {
return 1;
}

while (len--) {
*reg_data = (uint8_t)Wire.read();
reg_data++;
}

return 0;
}

/**
* The various initialization steps for this sensor.
*
*/
void HdcInit(void) {
HdcReset();
HdcConfig(HDC1080_MODE_ON);
}

/**
* Triggers the single transaction read of the T/RH sensor.
*
*/
bool HdcTriggerRead(void) {
int8_t status = HdcTransactionOpen(HDC1080_ADDR, HDC_REG_TEMP);

hdc_next_read = millis() + HDC1080_CONV_TIME;

if(status) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcTriggerRead: failed to open the transaction for HDC_REG_TEMP. Status = %d"), status);

return false;
}

is_reading = true;

Copy link
Collaborator

@s-hadinger s-hadinger Mar 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where you should put timer_hdc1080 = millis() + HDC1080_CONV_TIME;

return true;
}

/**
* Performs a temperature and humidity measurement, and calls
* the conversion function providing the results in the correct
* unit according to the device settings.
*
* returns: false if something failed during the read process.
*
*/
bool HdcRead(void) {
int8_t status = 0;
uint8_t sensor_data[4];
uint16_t temp_data = 0;
uint16_t rh_data = 0;

is_reading = false;

status = HdcTransactionClose(HDC1080_ADDR, sensor_data, 4);

if(status) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcRead: failed to read HDC_REG_TEMP. Status = %d"), status);

return false;
}

temp_data = (uint16_t) ((sensor_data[0] << 8) | sensor_data[1]);
rh_data = (uint16_t) ((sensor_data[2] << 8) | sensor_data[3]);

AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature raw data: 0x%04x; humidity raw data: 0x%04x"), temp_data, rh_data);

// read the temperature from the first 16 bits of the result

hdc_temperature = ConvertTemp(HDC1080_TEMP_MULT * (float) (temp_data) - HDC1080_TEMP_OFFSET);

hdc_humidity = HDC1080_RH_MULT * (float) (rh_data);

if (hdc_humidity > 100) { hdc_humidity = 100.0; }
if (hdc_humidity < 0) { hdc_humidity = 0.01; }

ConvertHumidity(hdc_humidity); // Set global humidity

hdc_valid = SENSOR_MAX_MISS;

return true;
}

/**
* Performs the detection of the HTC1080 sensor.
*
*/

void HdcDetect(void) {
if (I2cActive(HDC1080_ADDR)) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcDetect: Address = 0x%02X already in use."), HDC1080_ADDR);

return;
}

hdc_manufacturer_id = HdcReadManufacturerId();
hdc_device_id = HdcReadDeviceId();

AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcDetect: detected device with manufacturerId = 0x%04X and deviceId = 0x%04X"), hdc_manufacturer_id, hdc_device_id);

if (hdc_device_id == HDC1080_DEV_ID) {
HdcInit();
I2cSetActiveFound(HDC1080_ADDR, hdc_type_name);
}
}

/**
* As the name suggests, this function is called every second
* for performing driver related logic.
*
*/
void HdcEverySecond(void) {
if (uptime &1) { // Every 2 seconds
if (!HdcTriggerRead()) {
AddLogMissed((char*) hdc_type_name, hdc_valid);
}
}
}

/**
* Tasmota boilerplate for presenting the sensor data in the web UI, JSON for
* the MQTT messages, and so on.
*
*/
void HdcShow(bool json) {
if (hdc_valid) {
char temperature[33];

dtostrfd(hdc_temperature, Settings.flag2.temperature_resolution, temperature);
char humidity[33];
dtostrfd(hdc_humidity, Settings.flag2.humidity_resolution, humidity);

if (json) {
ResponseAppend_P(JSON_SNS_TEMPHUM, hdc_type_name, temperature, humidity);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzTempHumSensor(temperature, humidity);
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, hdc_temperature);
KnxSensor(KNX_HUMIDITY, hdc_humidity);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_SNS_TEMP, hdc_type_name, temperature, TempUnit());
WSContentSend_PD(HTTP_SNS_HUM, hdc_type_name, humidity);
#endif // USE_WEBSERVER
}
}
}

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

bool Xsns65(uint8_t function)
{
if (!I2cEnabled(XI2C_45)) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("Xsns65: I2C driver not enabled for this device."));

return false;
}

bool result = false;

if (FUNC_INIT == function) {
HdcDetect();
}
else if (hdc_device_id) {
switch (function) {
case FUNC_EVERY_50_MSECOND:
if(is_reading && TimeReached(hdc_next_read)) {
if(!HdcRead()) {
AddLogMissed((char*) hdc_type_name, hdc_valid);
}
}
break;
case FUNC_EVERY_SECOND:
HdcEverySecond();
break;
case FUNC_JSON_APPEND:
HdcShow(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
HdcShow(0);
break;
#endif // USE_WEBSERVER
}
}
return result;
}

#endif // USE_HDC1080
#endif // USE_I2C