Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
5.1 KiB

  1. // -----------------------------------------------------------------------------
  2. // HDC1080 / 831R Sensor over I2C
  3. // Based on SI7021 / HTU21D Sensor over I2C
  4. // Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
  5. // Copyright (C) 2020 by Alexander Kolesnikov <vtochq at gmail dot com>
  6. // -----------------------------------------------------------------------------
  7. #if SENSOR_SUPPORT && HDC1080_SUPPORT
  8. #pragma once
  9. #include "I2CSensor.h"
  10. #include "../utils.h"
  11. #define HDC1080_SCL_FREQUENCY 200
  12. // ref. http://www.ti.com/lit/ds/symlink/hdc1080.pdf
  13. // Device ID. Should be the same for every device.
  14. #define HDC1080_DEVICE_ID 0x1050
  15. #define HDC1080_CMD_TMP 0x00
  16. #define HDC1080_CMD_HUM 0x01
  17. class HDC1080Sensor : public I2CSensor<> {
  18. public:
  19. // ---------------------------------------------------------------------
  20. // Public
  21. // ---------------------------------------------------------------------
  22. HDC1080Sensor() {
  23. _sensor_id = SENSOR_HDC1080_ID;
  24. }
  25. // ---------------------------------------------------------------------
  26. // Sensor API
  27. // ---------------------------------------------------------------------
  28. // Initialization method, must be idempotent
  29. void begin() {
  30. if (!_dirty) return;
  31. _init();
  32. _dirty = !_ready;
  33. }
  34. // Descriptive name of the sensor
  35. String description() {
  36. char buffer[25];
  37. snprintf_P(buffer, sizeof(buffer), PSTR("HDC1080 @ I2C (0x%02X)"), _address);
  38. return String(buffer);
  39. }
  40. // Descriptive name of the slot # index
  41. String description(unsigned char index) {
  42. return description();
  43. };
  44. // Type for slot # index
  45. unsigned char type(unsigned char index) {
  46. if (index == 0) return MAGNITUDE_TEMPERATURE;
  47. if (index == 1) return MAGNITUDE_HUMIDITY;
  48. return MAGNITUDE_NONE;
  49. }
  50. // Pre-read hook (usually to populate registers with up-to-date data)
  51. void pre() {
  52. _error = SENSOR_ERROR_OK;
  53. double value;
  54. value = _read(HDC1080_CMD_TMP);
  55. if (_error != SENSOR_ERROR_OK) return;
  56. _temperature = (165 * value / 65536) - 40;
  57. value = _read(HDC1080_CMD_HUM);
  58. if (_error != SENSOR_ERROR_OK) return;
  59. value = (value / 65536)*100;
  60. _humidity = constrain(value, 0, 100);
  61. }
  62. // Current value for slot # index
  63. double value(unsigned char index) {
  64. if (index == 0) return _temperature;
  65. if (index == 1) return _humidity;
  66. return 0;
  67. }
  68. protected:
  69. // ---------------------------------------------------------------------
  70. // Protected
  71. // ---------------------------------------------------------------------
  72. void _init() {
  73. // I2C auto-discover
  74. unsigned char addresses[] = {0x40};
  75. _address = _begin_i2c(_address, sizeof(addresses), addresses);
  76. if (_address == 0) return;
  77. // Check device ID before doing anything else
  78. // ref. https://github.com/xoseperez/espurna/issues/2270#issuecomment-639239944
  79. // > Also there are clones of HDC1080 and they may have different Device ID
  80. // > values. You need to check it by reading and debug output this bytes.
  81. i2c_write_uint8(_address, 0xFF);
  82. _device_id = i2c_read_uint16(_address);
  83. if (_device_id == HDC1080_DEVICE_ID) {
  84. _ready = true;
  85. _count = 2;
  86. return;
  87. }
  88. DEBUG_MSG_P(PSTR("[HDC1080] ERROR: Expected Device ID %04X, received %04X\n"), HDC1080_DEVICE_ID, _device_id);
  89. _count = 0;
  90. i2cReleaseLock(_address);
  91. _previous_address = 0;
  92. _error = SENSOR_ERROR_UNKNOWN_ID;
  93. // Setting _address to 0 forces auto-discover
  94. // This might be necessary at this stage if there is a
  95. // different sensor in the hardcoded address
  96. _address = 0;
  97. _ready = false;
  98. }
  99. unsigned int _read(uint8_t command) {
  100. // Request measurement
  101. i2c_write_uint8(_address, command);
  102. // When not using clock stretching (*_NOHOLD commands) delay here
  103. // is needed to wait for the measurement.
  104. // According to datasheet the max. conversion time is ~22ms
  105. nice_delay(50);
  106. // Clear the last to bits of LSB to 00.
  107. // According to datasheet LSB of Temp and RH is always xxxxxx00
  108. unsigned int value = i2c_read_uint16(_address) & 0xFFFC;
  109. // We should be checking there are no pending bytes in the buffer
  110. // and raise a CRC error if there are
  111. _error = SENSOR_ERROR_OK;
  112. return value;
  113. }
  114. uint16_t _device_id = 0;
  115. double _temperature = 0;
  116. double _humidity = 0;
  117. };
  118. #endif // SENSOR_SUPPORT && HDC1080_SUPPORT