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.

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