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.

152 lines
4.4 KiB

  1. // -----------------------------------------------------------------------------
  2. // ADS121-based Energy Monitor Sensor over I2C
  3. // Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. // -----------------------------------------------------------------------------
  5. #if SENSOR_SUPPORT && EMON_ADC121_SUPPORT
  6. #pragma once
  7. #include "../utils.h"
  8. #include "EmonSensor.h"
  9. // ADC121 Registers
  10. #define ADC121_REG_RESULT 0x00
  11. #define ADC121_REG_ALERT 0x01
  12. #define ADC121_REG_CONFIG 0x02
  13. #define ADC121_REG_LIMITL 0x03
  14. #define ADC121_REG_LIMITH 0x04
  15. #define ADC121_REG_HYST 0x05
  16. #define ADC121_REG_CONVL 0x06
  17. #define ADC121_REG_CONVH 0x07
  18. #define ADC121_RESOLUTION 12
  19. #define ADC121_CHANNELS 1
  20. class EmonADC121Sensor : public EmonSensor {
  21. public:
  22. // ---------------------------------------------------------------------
  23. // Public
  24. // ---------------------------------------------------------------------
  25. EmonADC121Sensor() {
  26. _channels = ADC121_CHANNELS;
  27. _sensor_id = SENSOR_EMON_ADC121_ID;
  28. init();
  29. }
  30. // ---------------------------------------------------------------------
  31. // Sensor API
  32. // ---------------------------------------------------------------------
  33. // Initialization method, must be idempotent
  34. void begin() {
  35. if (!_dirty) return;
  36. _dirty = false;
  37. // Discover
  38. unsigned char addresses[] = {0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x58, 0x59, 0x5A};
  39. _address = _begin_i2c(_address, sizeof(addresses), addresses);
  40. if (_address == 0) return;
  41. // Init sensor
  42. _init();
  43. // Just one channel
  44. _count = _magnitudes;
  45. // Bit depth
  46. _resolution = ADC121_RESOLUTION;
  47. // Call the parent class method
  48. EmonSensor::begin();
  49. // warmup channel 0 (the only one)
  50. read(0);
  51. }
  52. // Descriptive name of the sensor
  53. String description() {
  54. char buffer[30];
  55. snprintf(buffer, sizeof(buffer), "EMON @ ADC121 @ I2C (0x%02X)", _address);
  56. return String(buffer);
  57. }
  58. // Pre-read hook (usually to populate registers with up-to-date data)
  59. void pre() {
  60. if (_address == 0) {
  61. _error = SENSOR_ERROR_UNKNOWN_ID;
  62. return;
  63. }
  64. // only 1 channel, see ADC121_CHANNELS
  65. _current[0] = read(0);
  66. #if EMON_REPORT_ENERGY
  67. static unsigned long last = 0;
  68. _energy[0] += sensor::Ws {
  69. static_cast<uint32_t>(_current[0] * _voltage * (millis() - last) / 1000)
  70. };
  71. last = millis();
  72. #endif
  73. _error = SENSOR_ERROR_OK;
  74. }
  75. // Type for slot # index
  76. unsigned char type(unsigned char index) {
  77. unsigned char i=0;
  78. #if EMON_REPORT_CURRENT
  79. if (index == i++) return MAGNITUDE_CURRENT;
  80. #endif
  81. #if EMON_REPORT_POWER
  82. if (index == i++) return MAGNITUDE_POWER_APPARENT;
  83. #endif
  84. #if EMON_REPORT_ENERGY
  85. if (index == i) return MAGNITUDE_ENERGY;
  86. #endif
  87. return MAGNITUDE_NONE;
  88. }
  89. // Current value for slot # index
  90. double value(unsigned char index) {
  91. unsigned char channel = local(index);
  92. unsigned char i=0;
  93. #if EMON_REPORT_CURRENT
  94. if (index == i++) return _current[channel];
  95. #endif
  96. #if EMON_REPORT_POWER
  97. if (index == i++) return _current[channel] * _voltage;
  98. #endif
  99. #if EMON_REPORT_ENERGY
  100. if (index == i) return _energy[channel].asDouble();
  101. #endif
  102. return 0;
  103. }
  104. protected:
  105. // ---------------------------------------------------------------------
  106. // Protected
  107. // ---------------------------------------------------------------------
  108. void _init() {
  109. i2c_write_uint8(_address, ADC121_REG_CONFIG, 0);
  110. }
  111. unsigned int readADC(unsigned char) {
  112. unsigned int value = i2c_read_uint16(_address, ADC121_REG_RESULT) & 0x0FFF;
  113. return value;
  114. }
  115. };
  116. #endif // SENSOR_SUPPORT && EMON_ADC121_SUPPORT