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.

260 lines
9.0 KiB

  1. // -----------------------------------------------------------------------------
  2. // ADE7853 Sensor over I2C
  3. // Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. // Implemented by Antonio López <tonilopezmr at gmail dot com>
  5. // -----------------------------------------------------------------------------
  6. #if SENSOR_SUPPORT && ADE7953_SUPPORT
  7. #pragma once
  8. #include "BaseEmonSensor.h"
  9. #include "I2CSensor.h"
  10. #include "../utils.h"
  11. #include <Wire.h>
  12. // -----------------------------------------------------------------------------
  13. // ADE7953 - Energy (Shelly 2.5)
  14. //
  15. // Based on datasheet from https://www.analog.com/en/products/ade7953.html
  16. // Based on Tasmota code https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/xnrg_07_ade7953.ino
  17. //
  18. // I2C Address: 0x38
  19. // -----------------------------------------------------------------------------
  20. #define ADE7953_PREF 1540
  21. #define ADE7953_UREF 26000
  22. #define ADE7953_IREF 10000
  23. #define ADE7953_ALL_RELAYS 0
  24. #define ADE7953_RELAY_1 1
  25. #define ADE7953_RELAY_2 2
  26. #define ADE7953_VOLTAGE 1
  27. #define ADE7953_TOTAL_DEVICES 3
  28. class ADE7953Sensor : public I2CSensor<BaseEmonSensor> {
  29. protected:
  30. struct reading_t {
  31. float current = 0.0;
  32. float power = 0.0;
  33. };
  34. public:
  35. // ---------------------------------------------------------------------
  36. // Public
  37. // ---------------------------------------------------------------------
  38. ADE7953Sensor() {
  39. resizeDevices(ADE7953_TOTAL_DEVICES);
  40. _sensor_id = SENSOR_ADE7953_ID;
  41. _readings.resize(countDevices());
  42. _count = _readings.size() * countDevices() + ADE7953_VOLTAGE; //10
  43. }
  44. // ---------------------------------------------------------------------
  45. // Sensors API
  46. // ---------------------------------------------------------------------
  47. // Initialization method, must be idempotent
  48. void begin() {
  49. if (!_dirty) return;
  50. _init();
  51. _dirty = !_ready;
  52. }
  53. // Descriptive name of the sensor
  54. String description() {
  55. char buffer[25];
  56. snprintf(buffer, sizeof(buffer), "ADE7953 @ I2C (0x%02X)", _address);
  57. return String(buffer);
  58. }
  59. // Descriptive name of the slot # index
  60. String description(unsigned char index) {
  61. return description();
  62. };
  63. // Pre-read hook (usually to populate registers with up-to-date data)
  64. void pre() {
  65. uint32_t active_power1 = 0;
  66. uint32_t active_power2 = 0;
  67. uint32_t current_rms1 = 0;
  68. uint32_t current_rms2 = 0;
  69. uint32_t voltage_rms = 0;
  70. voltage_rms = read(_address, 0x31C); // Both relays
  71. current_rms1 = read(_address, 0x31B); // Relay 1
  72. if (current_rms1 < 2000) { // No load threshold (20mA)
  73. current_rms1 = 0;
  74. active_power1 = 0;
  75. } else {
  76. active_power1 = (int32_t)read(_address, 0x313) * -1; // Relay 1
  77. active_power1 = (active_power1 > 0) ? active_power1 : 0;
  78. }
  79. current_rms2 = read(_address, 0x31A); // Relay 2
  80. if (current_rms2 < 2000) { // No load threshold (20mA)
  81. current_rms2 = 0;
  82. active_power2 = 0;
  83. } else {
  84. active_power2 = (int32_t)read(_address, 0x312); // Relay 2
  85. active_power2 = (active_power2 > 0) ? active_power2 : 0;
  86. }
  87. _voltage = (float) voltage_rms / ADE7953_UREF;
  88. storeReading(
  89. ADE7953_ALL_RELAYS,
  90. (float)(current_rms1 + current_rms2) / (ADE7953_IREF * 10),
  91. (float)(active_power1 + active_power2) / (ADE7953_PREF / 10)
  92. );
  93. storeReading(
  94. ADE7953_RELAY_1,
  95. (float) current_rms1 / (ADE7953_IREF * 10),
  96. (float) active_power1 / (ADE7953_PREF / 10)
  97. );
  98. storeReading(
  99. ADE7953_RELAY_2,
  100. (float)current_rms2 / (ADE7953_IREF * 10),
  101. (float)active_power2 / (ADE7953_PREF / 10)
  102. );
  103. }
  104. inline void storeReading(unsigned int relay, float current, float power) {
  105. auto& reading_ref = _readings.at(relay);
  106. reading_ref.current = current;
  107. reading_ref.power = power;
  108. // TODO: chip already stores precise data about energy, see datasheet
  109. static unsigned long last = 0;
  110. if (last > 0) {
  111. const uint32_t delta = (fabs(power) * (millis() - last) / 1000);
  112. _energy[relay] += sensor::Ws { delta };
  113. }
  114. last = millis();
  115. }
  116. // Current value for slot # index
  117. double value(unsigned char index) {
  118. if (index == 0) return _voltage;
  119. int relay = (index - 1) / countDevices();
  120. index = index % countDevices();
  121. if (index == 0) return getEnergy(relay);
  122. if (index == 1) return _readings[relay].current;
  123. if (index == 2) return _readings[relay].power;
  124. return 0;
  125. }
  126. // Convert slot # to a magnitude #
  127. unsigned char local(unsigned char index) override {
  128. if (index == 0) { return 0; } // common voltage
  129. return (index - 1) / countDevices(); // device { energy, current, active power }
  130. }
  131. // Type for slot # index
  132. unsigned char type(unsigned char index) {
  133. if (index == 0) return MAGNITUDE_VOLTAGE;
  134. index = index % countDevices();
  135. if (index == 0) return MAGNITUDE_ENERGY;
  136. if (index == 1) return MAGNITUDE_CURRENT;
  137. if (index == 2) return MAGNITUDE_POWER_ACTIVE;
  138. return MAGNITUDE_NONE;
  139. }
  140. protected:
  141. void _init() {
  142. // Need at least 100mS to init ADE7953.
  143. // TODO: add polling delay member instead of waiting right here?
  144. nice_delay(100);
  145. // Lock chip i2c address
  146. uint8_t addresses[] = { ADE7953_ADDRESS };
  147. _address = _begin_i2c(_address, sizeof(addresses), addresses);
  148. if (0 == _address) return;
  149. // TODO: we implement other i2c methods as local functions, as we need to address 16-bit registers
  150. // should eventually be replaced with i2c module alternatives.
  151. write(_address, 0x102, 0x0004); // Locking the communication interface (Clear bit COMM_LOCK), Enable HPF
  152. write(_address, 0x0FE, 0x00AD); // Unlock register 0x120
  153. write(_address, 0x120, 0x0030); // Configure optimum setting
  154. _ready = true;
  155. }
  156. #if 0
  157. static int reg_size(uint16_t reg) {
  158. int size = 0;
  159. switch ((reg >> 8) & 0x0F) {
  160. case 0x03:
  161. size++;
  162. case 0x02:
  163. size++;
  164. case 0x01:
  165. size++;
  166. case 0x00:
  167. case 0x07:
  168. case 0x08:
  169. size++;
  170. }
  171. return size;
  172. }
  173. #else
  174. // Optimized version of the function above, -80 bytes of code
  175. // Use the known property of register addresses to calculate their size
  176. static const int reg_size(const uint16_t reg) {
  177. const uint8_t mask = ((reg >> 8) & 0b1111);
  178. if (!mask || (mask & 0b1100)) {
  179. return 1;
  180. } else if (mask & 0b0011) {
  181. return mask + 1;
  182. }
  183. return 0;
  184. }
  185. #endif
  186. void write(unsigned char address, uint16_t reg, uint32_t val) {
  187. int size = reg_size(reg);
  188. if (size) {
  189. Wire.beginTransmission(address);
  190. Wire.write((reg >> 8) & 0xFF);
  191. Wire.write(reg & 0xFF);
  192. while (size--) {
  193. Wire.write((val >> (8 * size)) & 0xFF); // Write data, MSB first
  194. }
  195. Wire.endTransmission();
  196. delayMicroseconds(5); // Bus-free time minimum 4.7us
  197. }
  198. }
  199. static uint32_t read(int address, uint16_t reg) {
  200. uint32_t response = 0;
  201. const int size = reg_size(reg);
  202. if (size) {
  203. Wire.beginTransmission(address);
  204. Wire.write((reg >> 8) & 0xFF);
  205. Wire.write(reg & 0xFF);
  206. Wire.endTransmission(0);
  207. Wire.requestFrom(address, size);
  208. if (size <= Wire.available()) {
  209. for (int i = 0; i < size; i++) {
  210. response = response << 8 | Wire.read(); // receive DATA (MSB first)
  211. }
  212. }
  213. }
  214. return response;
  215. }
  216. float _voltage = 0;
  217. std::vector<reading_t> _readings;
  218. };
  219. #endif // SENSOR_SUPPORT && ADE7953_SUPPORT