├── ATM90E32.cpp ├── ATM90E32.h ├── README.md └── library.json /ATM90E32.cpp: -------------------------------------------------------------------------------- 1 | /* ATM90E32 Energy Monitor Functions 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2016 whatnick,Ryzee and Arun 6 | 7 | Modified to use with the CircuitSetup.us Split Phase Energy Meter by jdeglavina 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #include "ATM90E32.h" 17 | 18 | ATM90E32::ATM90E32(void){ 19 | } 20 | 21 | ATM90E32::~ATM90E32() { 22 | // end 23 | } 24 | 25 | /* CommEnergyIC - Communication Establishment */ 26 | /* 27 | - Defines Register Mask 28 | - Treats the Register and SPI Comms 29 | - Outputs the required value in the register 30 | */ 31 | unsigned short ATM90E32::CommEnergyIC(unsigned char RW, unsigned short address, unsigned short val) 32 | { 33 | unsigned char* data = (unsigned char*)&val; 34 | unsigned char* adata = (unsigned char*)&address; 35 | unsigned short output; 36 | unsigned short address1; 37 | 38 | //SPI interface rate is 200 to 160k bps. It will need to be slowed down for EnergyIC 39 | #if !defined(ENERGIA) && !defined(ESP8266) && !defined(ESP32) && !defined(ARDUINO_ARCH_SAMD) 40 | SPISettings settings(200000, MSBFIRST, SPI_MODE0); 41 | #endif 42 | 43 | #if defined(ESP8266) 44 | SPISettings settings(200000, MSBFIRST, SPI_MODE1); 45 | #endif 46 | 47 | #if defined(ESP32) 48 | SPISettings settings(200000, MSBFIRST, SPI_MODE3); 49 | #endif 50 | 51 | #if defined(ARDUINO_ARCH_SAMD) 52 | SPISettings settings(200000, MSBFIRST, SPI_MODE3); 53 | #endif 54 | 55 | // Switch MSB and LSB of value 56 | output = (val >> 8) | (val << 8); 57 | val = output; 58 | 59 | // Set R/W flag 60 | address |= RW << 15; 61 | 62 | // Swap byte address 63 | address1 = (address >> 8) | (address << 8); 64 | address = address1; 65 | 66 | // Transmit & Receive Data 67 | #if !defined(ENERGIA) 68 | SPI.beginTransaction(settings); 69 | #endif 70 | 71 | // Chip enable and wait for SPI activation 72 | digitalWrite(_cs, LOW); 73 | delayMicroseconds(10); 74 | 75 | // Write address byte by byte 76 | for (byte i = 0; i < 2; i++) 77 | { 78 | SPI.transfer(*adata); 79 | adata++; 80 | } 81 | 82 | /* Must wait 4 us for data to become valid */ 83 | delayMicroseconds(4); 84 | 85 | // READ Data 86 | // Do for each byte in transfer 87 | if (RW) 88 | { 89 | for (byte i = 0; i < 2; i++) 90 | { 91 | *data = SPI.transfer(0x00); 92 | data++; 93 | } 94 | } 95 | else 96 | { 97 | for (byte i = 0; i < 2; i++) 98 | { 99 | SPI.transfer(*data); 100 | data++; 101 | } 102 | } 103 | 104 | // Chip enable and wait for transaction to end 105 | digitalWrite(_cs, HIGH); 106 | delayMicroseconds(10); 107 | #if !defined(ENERGIA) 108 | SPI.endTransaction(); 109 | #endif 110 | 111 | output = (val >> 8) | (val << 8); // reverse MSB and LSB 112 | return output; 113 | } 114 | 115 | int ATM90E32::Read32Register(signed short regh_addr, signed short regl_addr) { 116 | int val, val_h, val_l; 117 | val_h = CommEnergyIC(READ, regh_addr, 0xFFFF); 118 | val_l = CommEnergyIC(READ, regl_addr, 0xFFFF); 119 | val = CommEnergyIC(READ, regh_addr, 0xFFFF); 120 | 121 | val = val_h << 16; 122 | val |= val_l; //concatenate the 2 registers to make 1 32 bit number 123 | 124 | return (val); 125 | } 126 | 127 | double ATM90E32::CalculateVIOffset(unsigned short regh_addr, unsigned short regl_addr /*, unsigned short offset_reg*/) { 128 | //for getting the lower registers of Voltage and Current and calculating the offset 129 | //should only be run when CT sensors are connected to the meter, 130 | //but not connected around wires 131 | uint32_t val, val_h, val_l; 132 | uint16_t offset; 133 | val_h = CommEnergyIC(READ, regh_addr, 0xFFFF); 134 | val_l = CommEnergyIC(READ, regl_addr, 0xFFFF); 135 | val = CommEnergyIC(READ, regh_addr, 0xFFFF); 136 | 137 | val = val_h << 16; //move high register up 16 bits 138 | val |= val_l; //concatenate the 2 registers to make 1 32 bit number 139 | val = val >> 7; //right shift 7 bits - lowest 7 get ignored - V & I registers need this 140 | val = (~val) + 1; //2s compliment 141 | 142 | offset = val; //keep lower 16 bits 143 | //CommEnergyIC(WRITE, offset_reg, (signed short)val); 144 | return uint16_t(offset); 145 | } 146 | 147 | double ATM90E32::CalculatePowerOffset(unsigned short regh_addr, unsigned short regl_addr /*, unsigned short offset_reg*/) { 148 | //for getting the lower registers of energy and calculating the offset 149 | //should only be run when CT sensors are connected to the meter, 150 | //but not connected around wires 151 | uint32_t val, val_h, val_l; 152 | uint16_t offset; 153 | val_h = CommEnergyIC(READ, regh_addr, 0xFFFF); 154 | val_l = CommEnergyIC(READ, regl_addr, 0xFFFF); 155 | val = CommEnergyIC(READ, regh_addr, 0xFFFF); 156 | 157 | val = val_h << 16; //move high register up 16 bits 158 | val |= val_l; //concatenate the 2 registers to make 1 32 bit number 159 | val = (~val) + 1; //2s compliment 160 | 161 | offset = val; //keep lower 16 bits 162 | //CommEnergyIC(WRITE, offset_reg, (signed short)val); 163 | return uint16_t(offset); 164 | } 165 | 166 | double ATM90E32::CalibrateVI(unsigned short reg, unsigned short actualVal) { 167 | //input the Voltage or Current register, and the actual value that it should be 168 | //actualVal can be from a calibration meter or known value from a power supply 169 | uint16_t gain, val, m, gainReg; 170 | //sample the reading 171 | val = CommEnergyIC(READ, reg, 0xFFFF); 172 | val += CommEnergyIC(READ, reg, 0xFFFF); 173 | val += CommEnergyIC(READ, reg, 0xFFFF); 174 | val += CommEnergyIC(READ, reg, 0xFFFF); 175 | 176 | //get value currently in gain register 177 | switch (reg) { 178 | case UrmsA: { 179 | gainReg = UgainA; } 180 | case UrmsB: { 181 | gainReg = UgainB; } 182 | case UrmsC: { 183 | gainReg = UgainC; } 184 | case IrmsA: { 185 | gainReg = IgainA; } 186 | case IrmsB: { 187 | gainReg = IgainB; } 188 | case IrmsC: { 189 | gainReg = IgainC; } 190 | } 191 | 192 | gain = CommEnergyIC(READ, gainReg, 0xFFFF); 193 | m = actualVal; 194 | m = ((m * gain) / val); 195 | gain = m; 196 | 197 | //write new value to gain register 198 | CommEnergyIC(WRITE, gainReg, gain); 199 | 200 | return(gain); 201 | } 202 | 203 | 204 | 205 | /* Parameters Functions*/ 206 | /* 207 | - Gets main electrical parameters, 208 | such as: Voltage, Current, Power, Energy, 209 | and Frequency, and Temperature 210 | 211 | */ 212 | // VOLTAGE 213 | double ATM90E32::GetLineVoltageA() { 214 | unsigned short voltage = CommEnergyIC(READ, UrmsA, 0xFFFF); 215 | return (double)voltage / 100; 216 | } 217 | double ATM90E32::GetLineVoltageB() { 218 | unsigned short voltage = CommEnergyIC(READ, UrmsB, 0xFFFF); 219 | return (double)voltage / 100; 220 | } 221 | double ATM90E32::GetLineVoltageC() { 222 | unsigned short voltage = CommEnergyIC(READ, UrmsC, 0xFFFF); 223 | return (double)voltage / 100; 224 | } 225 | 226 | // CURRENT 227 | double ATM90E32::GetLineCurrentA() { 228 | unsigned short current = CommEnergyIC(READ, IrmsA, 0xFFFF); 229 | return (double)current / 1000; 230 | } 231 | double ATM90E32::GetLineCurrentB() { 232 | unsigned short current = CommEnergyIC(READ, IrmsB, 0xFFFF); 233 | return (double)current / 1000; 234 | } 235 | double ATM90E32::GetLineCurrentC() { 236 | unsigned short current = CommEnergyIC(READ, IrmsC, 0xFFFF); 237 | return (double)current / 1000; 238 | } 239 | 240 | double ATM90E32::GetLineCurrentN() { 241 | unsigned short current = CommEnergyIC(READ, IrmsN, 0xFFFF); 242 | return (double)current / 1000; 243 | } 244 | 245 | // ACTIVE POWER 246 | double ATM90E32::GetActivePowerA() { 247 | int val = Read32Register(PmeanA, PmeanALSB); 248 | return (double)val * 0.00032; 249 | } 250 | double ATM90E32::GetActivePowerB() { 251 | int val = Read32Register(PmeanB, PmeanBLSB); 252 | return (double)val * 0.00032; 253 | } 254 | double ATM90E32::GetActivePowerC() { 255 | int val = Read32Register(PmeanC, PmeanCLSB); 256 | return (double)val * 0.00032; 257 | } 258 | double ATM90E32::GetTotalActivePower() { 259 | int val = Read32Register(PmeanT, PmeanTLSB); 260 | return (double)val * 0.00032; 261 | } 262 | 263 | // Active Fundamental Power 264 | double ATM90E32::GetTotalActiveFundPower() { 265 | int val = Read32Register(PmeanTF, PmeanTFLSB); 266 | return (double)val * 0.00032; 267 | } 268 | 269 | // Active Harmonic Power 270 | double ATM90E32::GetTotalActiveHarPower() { 271 | int val = Read32Register(PmeanTH, PmeanTHLSB); 272 | return (double)val * 0.00032; 273 | } 274 | 275 | 276 | // REACTIVE POWER 277 | double ATM90E32::GetReactivePowerA() { 278 | int val = Read32Register(QmeanA, QmeanALSB); 279 | return (double)val * 0.00032; 280 | } 281 | double ATM90E32::GetReactivePowerB() { 282 | int val = Read32Register(QmeanB, QmeanBLSB); 283 | return (double)val * 0.00032; 284 | } 285 | double ATM90E32::GetReactivePowerC() { 286 | int val = Read32Register(QmeanC, QmeanCLSB); 287 | return (double)val * 0.00032; 288 | } 289 | double ATM90E32::GetTotalReactivePower() { 290 | int val = Read32Register(QmeanT, QmeanTLSB); 291 | return (double)val * 0.00032; 292 | } 293 | 294 | // APPARENT POWER 295 | double ATM90E32::GetApparentPowerA() { 296 | int val = Read32Register(SmeanA, SmeanALSB); 297 | return (double)val * 0.00032; 298 | } 299 | double ATM90E32::GetApparentPowerB() { 300 | int val = Read32Register(SmeanB, SmeanBLSB); 301 | return (double)val * 0.00032; 302 | } 303 | double ATM90E32::GetApparentPowerC() { 304 | int val = Read32Register(SmeanC, SmeanCLSB); 305 | return (double)val * 0.00032; 306 | } 307 | double ATM90E32::GetTotalApparentPower() { 308 | int val = Read32Register(SmeanT, SAmeanTLSB); 309 | return (double)val * 0.00032; 310 | } 311 | 312 | // FREQUENCY 313 | double ATM90E32::GetFrequency() { 314 | unsigned short freq = CommEnergyIC(READ, Freq, 0xFFFF); 315 | return (double)freq / 100; 316 | } 317 | 318 | // POWER FACTOR 319 | double ATM90E32::GetPowerFactorA() { 320 | signed short pf = (signed short) CommEnergyIC(READ, PFmeanA, 0xFFFF); 321 | return (double)pf / 1000; 322 | } 323 | double ATM90E32::GetPowerFactorB() { 324 | signed short pf = (signed short) CommEnergyIC(READ, PFmeanB, 0xFFFF); 325 | return (double)pf / 1000; 326 | } 327 | double ATM90E32::GetPowerFactorC() { 328 | signed short pf = (signed short) CommEnergyIC(READ, PFmeanC, 0xFFFF); 329 | return (double)pf / 1000; 330 | } 331 | double ATM90E32::GetTotalPowerFactor() { 332 | signed short pf = (signed short) CommEnergyIC(READ, PFmeanT, 0xFFFF); 333 | return (double)pf / 1000; 334 | } 335 | 336 | // MEAN PHASE ANGLE 337 | double ATM90E32::GetPhaseA() { 338 | unsigned short angleA = (unsigned short) CommEnergyIC(READ, PAngleA, 0xFFFF); 339 | return (double)angleA / 10; 340 | } 341 | double ATM90E32::GetPhaseB() { 342 | unsigned short angleB = (unsigned short) CommEnergyIC(READ, PAngleB, 0xFFFF); 343 | return (double)angleB / 10; 344 | } 345 | double ATM90E32::GetPhaseC() { 346 | unsigned short angleC = (unsigned short) CommEnergyIC(READ, PAngleC, 0xFFFF); 347 | return (double)angleC / 10; 348 | } 349 | 350 | // TEMPERATURE 351 | double ATM90E32::GetTemperature() { 352 | short int atemp = (short int) CommEnergyIC(READ, Temp, 0xFFFF); 353 | return (double)atemp; 354 | } 355 | 356 | /* Gets the Register Value if Desired */ 357 | // REGISTER 358 | double ATM90E32::GetValueRegister(unsigned short registerRead) { 359 | return (double) CommEnergyIC(READ, registerRead, 0xFFFF); //returns value register 360 | } 361 | 362 | // REGULAR ENERGY MEASUREMENT 363 | 364 | // FORWARD ACTIVE ENERGY 365 | // these registers accumulate energy and are cleared after being read 366 | double ATM90E32::GetImportEnergy() { 367 | unsigned short ienergyT = CommEnergyIC(READ, APenergyT, 0xFFFF); 368 | return (double)ienergyT / 100 / 3200; //returns kWh 369 | } 370 | // unsigned short ienergyA = CommEnergyIC(READ, APenergyA, 0xFFFF); 371 | // unsigned short ienergyB = CommEnergyIC(READ, APenergyB, 0xFFFF); 372 | // unsigned short ienergyC = CommEnergyIC(READ, APenergyC, 0xFFFF); 373 | 374 | // FORWARD REACTIVE ENERGY 375 | double ATM90E32::GetImportReactiveEnergy() { 376 | unsigned short renergyT = CommEnergyIC(READ, RPenergyT, 0xFFFF); 377 | return (double)renergyT / 100 / 3200; //returns kWh 378 | } 379 | // unsigned short renergyA = CommEnergyIC(READ, RPenergyA, 0xFFFF); 380 | // unsigned short renergyB = CommEnergyIC(READ, RPenergyB, 0xFFFF); 381 | // unsigned short renergyC = CommEnergyIC(READ, RPenergyC, 0xFFFF); 382 | 383 | // APPARENT ENERGY 384 | double ATM90E32::GetImportApparentEnergy() { 385 | unsigned short senergyT = CommEnergyIC(READ, SAenergyT, 0xFFFF); 386 | return (double)senergyT / 100 / 3200; //returns kWh 387 | } 388 | // unsigned short senergyA = CommEnergyIC(READ, SenergyA, 0xFFFF); 389 | // unsigned short senergyB = CommEnergyIC(READ, SenergyB, 0xFFFF); 390 | // unsigned short senergyC = CommEnergyIC(READ, SenergyC, 0xFFFF); 391 | 392 | // REVERSE ACTIVE ENERGY 393 | double ATM90E32::GetExportEnergy() { 394 | unsigned short eenergyT = CommEnergyIC(READ, ANenergyT, 0xFFFF); 395 | return (double)eenergyT / 100 / 3200; //returns kWh 396 | } 397 | // unsigned short eenergyA = CommEnergyIC(READ, ANenergyA, 0xFFFF); 398 | // unsigned short eenergyB = CommEnergyIC(READ, ANenergyB, 0xFFFF); 399 | // unsigned short eenergyC = CommEnergyIC(READ, ANenergyC, 0xFFFF); 400 | 401 | // REVERSE REACTIVE ENERGY 402 | double ATM90E32::GetExportReactiveEnergy() { 403 | unsigned short reenergyT = CommEnergyIC(READ, RNenergyT, 0xFFFF); 404 | return (double)reenergyT / 100 / 3200; //returns kWh 405 | } 406 | // unsigned short reenergyA = CommEnergyIC(READ, RNenergyA, 0xFFFF); 407 | // unsigned short reenergyB = CommEnergyIC(READ, RNenergyB, 0xFFFF); 408 | // unsigned short reenergyC = CommEnergyIC(READ, RNenergyC, 0xFFFF); 409 | 410 | 411 | 412 | /* System Status Registers */ 413 | unsigned short ATM90E32::GetSysStatus0() { 414 | return CommEnergyIC(READ, EMMIntState0, 0xFFFF); 415 | } 416 | unsigned short ATM90E32::GetSysStatus1() { 417 | return CommEnergyIC(READ, EMMIntState1, 0xFFFF); 418 | } 419 | unsigned short ATM90E32::GetMeterStatus0() { 420 | return CommEnergyIC(READ, EMMState0, 0xFFFF); 421 | } 422 | unsigned short ATM90E32::GetMeterStatus1() { 423 | return CommEnergyIC(READ, EMMState1, 0xFFFF); 424 | } 425 | 426 | /* BEGIN FUNCTION */ 427 | /* 428 | - Define the pin to be used as Chip Select 429 | - Set serialFlag to true for serial debugging 430 | - Use SPI MODE 0 for the ATM90E32 431 | */ 432 | void ATM90E32::begin(int pin, unsigned short lineFreq, unsigned short pgagain, unsigned short ugain, unsigned short igainA, unsigned short igainB, unsigned short igainC) 433 | { 434 | _cs = pin; // SS PIN 435 | _lineFreq = lineFreq; //frequency of power 436 | _pgagain = pgagain; //PGA Gain for current channels 437 | _ugain = ugain; //voltage rms gain 438 | _igainA = igainA; //CT1 439 | _igainB = igainB; //CT2 - not used for single split phase meter 440 | _igainC = igainC; //CT2 for single split phase meter - CT3 otherwise 441 | 442 | pinMode(_cs, OUTPUT); 443 | 444 | /* Enable SPI */ 445 | SPI.begin(); 446 | 447 | Serial.println("Connecting to ATM90E32"); 448 | #if defined(ENERGIA) 449 | SPI.setBitOrder(MSBFIRST); 450 | SPI.setDataMode(SPI_MODE0); 451 | SPI.setClockDivider(SPI_CLOCK_DIV16); 452 | #endif 453 | 454 | //calculation for voltage sag threshold - assumes we do not want to go under 90v for split phase and 190v otherwise 455 | //determine proper low and high frequency threshold 456 | unsigned short vSagTh; 457 | unsigned short sagV; 458 | unsigned short FreqHiThresh; 459 | unsigned short FreqLoThresh; 460 | if (_lineFreq == 4485 || _lineFreq == 4231) 461 | { 462 | sagV = 90; 463 | FreqHiThresh = 61 * 100; 464 | FreqLoThresh = 59 * 100; 465 | } 466 | else 467 | { 468 | sagV = 190; 469 | FreqHiThresh = 51 * 100; 470 | FreqLoThresh = 49 * 100; 471 | } 472 | 473 | vSagTh = (sagV * 100 * sqrt(2)) / (2 * _ugain / 32768); 474 | 475 | //Initialize registers 476 | CommEnergyIC(WRITE, SoftReset, 0x789A); // 70 Perform soft reset 477 | CommEnergyIC(WRITE, CfgRegAccEn, 0x55AA); // 7F enable register config access 478 | CommEnergyIC(WRITE, MeterEn, 0x0001); // 00 Enable Metering 479 | 480 | CommEnergyIC(WRITE, SagPeakDetCfg, 0x143F); // 05 Sag and Voltage peak detect period set to 20ms 481 | CommEnergyIC(WRITE, SagTh, vSagTh); // 08 Voltage sag threshold 482 | CommEnergyIC(WRITE, FreqHiTh, FreqHiThresh); // 0D High frequency threshold 483 | CommEnergyIC(WRITE, FreqLoTh, FreqLoThresh); // 0C Lo frequency threshold 484 | CommEnergyIC(WRITE, EMMIntEn0, 0xB76F); // 75 Enable interrupts 485 | CommEnergyIC(WRITE, EMMIntEn1, 0xDDFD); // 76 Enable interrupts 486 | CommEnergyIC(WRITE, EMMIntState0, 0x0001); // 73 Clear interrupt flags 487 | CommEnergyIC(WRITE, EMMIntState1, 0x0001); // 74 Clear interrupt flags 488 | CommEnergyIC(WRITE, ZXConfig, 0xD654); // 07 ZX2, ZX1, ZX0 pin config - set to current channels, all polarity 489 | 490 | //Set metering config values (CONFIG) 491 | CommEnergyIC(WRITE, PLconstH, 0x0861); // 31 PL Constant MSB (default) - Meter Constant = 3200 - PL Constant = 140625000 492 | CommEnergyIC(WRITE, PLconstL, 0xC468); // 32 PL Constant LSB (default) - this is 4C68 in the application note, which is incorrect 493 | CommEnergyIC(WRITE, MMode0, _lineFreq); // 33 Mode Config (frequency set in main program) 494 | CommEnergyIC(WRITE, MMode1, _pgagain); // 34 PGA Gain Configuration for Current Channels - 0x002A (x4) // 0x0015 (x2) // 0x0000 (1x) 495 | CommEnergyIC(WRITE, PStartTh, 0x1D4C); // 35 All phase Active Startup Power Threshold - 50% of startup current = 0.02A/0.00032 = 7500 496 | CommEnergyIC(WRITE, QStartTh, 0x1D4C); // 36 All phase Reactive Startup Power Threshold 497 | CommEnergyIC(WRITE, SStartTh, 0x1D4C); // 37 All phase Apparent Startup Power Threshold 498 | CommEnergyIC(WRITE, PPhaseTh, 0x02EE); // 38 Each phase Active Phase Threshold = 10% of startup current = 0.002A/0.00032 = 750 499 | CommEnergyIC(WRITE, QPhaseTh, 0x02EE); // 39 Each phase Reactive Phase Threshold 500 | CommEnergyIC(WRITE, SPhaseTh, 0x02EE); // 3A Each phase Apparent Phase Threshold 501 | 502 | //Set metering calibration values (CALIBRATION) 503 | CommEnergyIC(WRITE, PQGainA, 0x0000); // 47 Line calibration gain 504 | CommEnergyIC(WRITE, PhiA, 0x0000); // 48 Line calibration angle 505 | CommEnergyIC(WRITE, PQGainB, 0x0000); // 49 Line calibration gain 506 | CommEnergyIC(WRITE, PhiB, 0x0000); // 4A Line calibration angle 507 | CommEnergyIC(WRITE, PQGainC, 0x0000); // 4B Line calibration gain 508 | CommEnergyIC(WRITE, PhiC, 0x0000); // 4C Line calibration angle 509 | CommEnergyIC(WRITE, PoffsetA, 0x0000); // 41 A line active power offset FFDC 510 | CommEnergyIC(WRITE, QoffsetA, 0x0000); // 42 A line reactive power offset 511 | CommEnergyIC(WRITE, PoffsetB, 0x0000); // 43 B line active power offset 512 | CommEnergyIC(WRITE, QoffsetB, 0x0000); // 44 B line reactive power offset 513 | CommEnergyIC(WRITE, PoffsetC, 0x0000); // 45 C line active power offset 514 | CommEnergyIC(WRITE, QoffsetC, 0x0000); // 46 C line reactive power offset 515 | 516 | //Set metering calibration values (HARMONIC) 517 | CommEnergyIC(WRITE, POffsetAF, 0x0000); // 51 A Fund. active power offset 518 | CommEnergyIC(WRITE, POffsetBF, 0x0000); // 52 B Fund. active power offset 519 | CommEnergyIC(WRITE, POffsetCF, 0x0000); // 53 C Fund. active power offset 520 | CommEnergyIC(WRITE, PGainAF, 0x0000); // 54 A Fund. active power gain 521 | CommEnergyIC(WRITE, PGainBF, 0x0000); // 55 B Fund. active power gain 522 | CommEnergyIC(WRITE, PGainCF, 0x0000); // 56 C Fund. active power gain 523 | 524 | //Set measurement calibration values (ADJUST) 525 | CommEnergyIC(WRITE, UgainA, _ugain); // 61 A Voltage rms gain 526 | CommEnergyIC(WRITE, IgainA, _igainA); // 62 A line current gain 527 | CommEnergyIC(WRITE, UoffsetA, 0x0000); // 63 A Voltage offset - 61A8 528 | CommEnergyIC(WRITE, IoffsetA, 0x0000); // 64 A line current offset - FE60 529 | CommEnergyIC(WRITE, UgainB, _ugain); // 65 B Voltage rms gain 530 | CommEnergyIC(WRITE, IgainB, _igainB); // 66 B line current gain 531 | CommEnergyIC(WRITE, UoffsetB, 0x0000); // 67 B Voltage offset - 1D4C 532 | CommEnergyIC(WRITE, IoffsetB, 0x0000); // 68 B line current offset - FE60 533 | CommEnergyIC(WRITE, UgainC, _ugain); // 69 C Voltage rms gain 534 | CommEnergyIC(WRITE, IgainC, _igainC); // 6A C line current gain 535 | CommEnergyIC(WRITE, UoffsetC, 0x0000); // 6B C Voltage offset - 1D4C 536 | CommEnergyIC(WRITE, IoffsetC, 0x0000); // 6C C line current offset 537 | 538 | CommEnergyIC(WRITE, CfgRegAccEn, 0x0000); // 7F end configuration 539 | } 540 | -------------------------------------------------------------------------------- /ATM90E32.h: -------------------------------------------------------------------------------- 1 | /* ATM90E32 Energy Monitor Functions 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2016 whatnick,Ryzee and Arun 6 | 7 | Modified to use with the CircuitSetup.us Split Phase Energy Meter by jdeglavina 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | */ 15 | 16 | #ifndef ATM90E32_h 17 | #define ATM90E32_h 18 | #include 19 | #include 20 | 21 | #define WRITE 0 // WRITE SPI 22 | #define READ 1 // READ SPI 23 | #define DEBUG_SERIAL 1 24 | 25 | /* STATUS REGISTERS */ 26 | #define MeterEn 0x00 // Metering Enable 27 | #define ChannelMapI 0x01 // Current Channel Mapping Configuration 28 | #define ChannelMapU 0x02 // Voltage Channel Mapping Configuration 29 | #define SagPeakDetCfg 0x05 // Sag and Peak Detector Period Configuration 30 | #define OVth 0x06 // Over Voltage Threshold 31 | #define ZXConfig 0x07 // Zero-Crossing Config 32 | #define SagTh 0x08 // Voltage Sag Th 33 | #define PhaseLossTh 0x09 // Voltage Phase Losing Th 34 | #define INWarnTh 0x0A // Neutral Current (Calculated) Warning Threshold 35 | #define OIth 0x0B // Over Current Threshold 36 | #define FreqLoTh 0x0C // Low Threshold for Frequency Detection 37 | #define FreqHiTh 0x0D // High Threshold for Frequency Detection 38 | #define PMPwrCtrl 0x0E // Partial Measurement Mode Power Control 39 | #define IRQ0MergeCfg 0x0F // IRQ0 Merge Configuration 40 | 41 | /* EMM STATUS REGISTERS */ 42 | #define SoftReset 0x70 // Software Reset 43 | #define EMMState0 0x71 // EMM State 0 44 | #define EMMState1 0x72 // EMM State 1 45 | #define EMMIntState0 0x73 // EMM Interrupt Status 0 46 | #define EMMIntState1 0x74 // EMM Interrupt Status 1 47 | #define EMMIntEn0 0x75 // EMM Interrupt Enable 0 48 | #define EMMIntEn1 0x76 // EMM Interrupt Enable 1 49 | #define LastSPIData 0x78 // Last Read/Write SPI Value 50 | #define CRCErrStatus 0x79 // CRC Error Status 51 | #define CRCDigest 0x7A // CRC Digest 52 | #define CfgRegAccEn 0x7F // Configure Register Access Enable 53 | 54 | /* LOW POWER MODE REGISTERS - NOT USED */ 55 | #define DetectCtrl 0x10 56 | #define DetectTh1 0x11 57 | #define DetectTh2 0x12 58 | #define DetectTh3 0x13 59 | #define PMOffsetA 0x14 60 | #define PMOffsetB 0x15 61 | #define PMOffsetC 0x16 62 | #define PMPGA 0x17 63 | #define PMIrmsA 0x18 64 | #define PMIrmsB 0x19 65 | #define PMIrmsC 0x1A 66 | #define PMConfig 0x10B 67 | #define PMAvgSamples 0x1C 68 | #define PMIrmsLSB 0x1D 69 | 70 | /* CONFIGURATION REGISTERS */ 71 | #define PLconstH 0x31 // High Word of PL_Constant 72 | #define PLconstL 0x32 // Low Word of PL_Constant 73 | #define MMode0 0x33 // Metering Mode Config 74 | #define MMode1 0x34 // PGA Gain Configuration for Current Channels 75 | #define PStartTh 0x35 // Startup Power Th (P) 76 | #define QStartTh 0x36 // Startup Power Th (Q) 77 | #define SStartTh 0x37 // Startup Power Th (S) 78 | #define PPhaseTh 0x38 // Startup Power Accum Th (P) 79 | #define QPhaseTh 0x39 // Startup Power Accum Th (Q) 80 | #define SPhaseTh 0x3A // Startup Power Accum Th (S) 81 | 82 | /* CALIBRATION REGISTERS */ 83 | #define PoffsetA 0x41 // A Line Power Offset (P) 84 | #define QoffsetA 0x42 // A Line Power Offset (Q) 85 | #define PoffsetB 0x43 // B Line Power Offset (P) 86 | #define QoffsetB 0x44 // B Line Power Offset (Q) 87 | #define PoffsetC 0x45 // C Line Power Offset (P) 88 | #define QoffsetC 0x46 // C Line Power Offset (Q) 89 | #define PQGainA 0x47 // A Line Calibration Gain 90 | #define PhiA 0x48 // A Line Calibration Angle 91 | #define PQGainB 0x49 // B Line Calibration Gain 92 | #define PhiB 0x4A // B Line Calibration Angle 93 | #define PQGainC 0x4B // C Line Calibration Gain 94 | #define PhiC 0x4C // C Line Calibration Angle 95 | 96 | /* FUNDAMENTAL/HARMONIC ENERGY CALIBRATION REGISTERS */ 97 | #define POffsetAF 0x51 // A Fund Power Offset (P) 98 | #define POffsetBF 0x52 // B Fund Power Offset (P) 99 | #define POffsetCF 0x53 // C Fund Power Offset (P) 100 | #define PGainAF 0x54 // A Fund Power Gain (P) 101 | #define PGainBF 0x55 // B Fund Power Gain (P) 102 | #define PGainCF 0x56 // C Fund Power Gain (P) 103 | 104 | /* MEASUREMENT CALIBRATION REGISTERS */ 105 | #define UgainA 0x61 // A Voltage RMS Gain 106 | #define IgainA 0x62 // A Current RMS Gain 107 | #define UoffsetA 0x63 // A Voltage Offset 108 | #define IoffsetA 0x64 // A Current Offset 109 | #define UgainB 0x65 // B Voltage RMS Gain 110 | #define IgainB 0x66 // B Current RMS Gain 111 | #define UoffsetB 0x67 // B Voltage Offset 112 | #define IoffsetB 0x68 // B Current Offset 113 | #define UgainC 0x69 // C Voltage RMS Gain 114 | #define IgainC 0x6A // C Current RMS Gain 115 | #define UoffsetC 0x6B // C Voltage Offset 116 | #define IoffsetC 0x6C // C Current Offset 117 | #define IoffsetN 0x6E // N Current Offset 118 | 119 | /* ENERGY REGISTERS */ 120 | #define APenergyT 0x80 // Total Forward Active 121 | #define APenergyA 0x81 // A Forward Active 122 | #define APenergyB 0x82 // B Forward Active 123 | #define APenergyC 0x83 // C Forward Active 124 | #define ANenergyT 0x84 // Total Reverse Active 125 | #define ANenergyA 0x85 // A Reverse Active 126 | #define ANenergyB 0x86 // B Reverse Active 127 | #define ANenergyC 0x87 // C Reverse Active 128 | #define RPenergyT 0x88 // Total Forward Reactive 129 | #define RPenergyA 0x89 // A Forward Reactive 130 | #define RPenergyB 0x8A // B Forward Reactive 131 | #define RPenergyC 0x8B // C Forward Reactive 132 | #define RNenergyT 0x8C // Total Reverse Reactive 133 | #define RNenergyA 0x8D // A Reverse Reactive 134 | #define RNenergyB 0x8E // B Reverse Reactive 135 | #define RNenergyC 0x8F // C Reverse Reactive 136 | 137 | #define SAenergyT 0x90 // Total Apparent Energy 138 | #define SenergyA 0x91 // A Apparent Energy 139 | #define SenergyB 0x92 // B Apparent Energy 140 | #define SenergyC 0x93 // C Apparent Energy 141 | 142 | 143 | /* FUNDAMENTAL / HARMONIC ENERGY REGISTERS */ 144 | #define APenergyTF 0xA0 // Total Forward Fund. Energy 145 | #define APenergyAF 0xA1 // A Forward Fund. Energy 146 | #define APenergyBF 0xA2 // B Forward Fund. Energy 147 | #define APenergyCF 0xA3 // C Forward Fund. Energy 148 | #define ANenergyTF 0xA4 // Total Reverse Fund Energy 149 | #define ANenergyAF 0xA5 // A Reverse Fund. Energy 150 | #define ANenergyBF 0xA6 // B Reverse Fund. Energy 151 | #define ANenergyCF 0xA7 // C Reverse Fund. Energy 152 | #define APenergyTH 0xA8 // Total Forward Harm. Energy 153 | #define APenergyAH 0xA9 // A Forward Harm. Energy 154 | #define APenergyBH 0xAA // B Forward Harm. Energy 155 | #define APenergyCH 0xAB // C Forward Harm. Energy 156 | #define ANenergyTH 0xAC // Total Reverse Harm. Energy 157 | #define ANenergyAH 0xAD // A Reverse Harm. Energy 158 | #define ANenergyBH 0xAE // B Reverse Harm. Energy 159 | #define ANenergyCH 0xAF // C Reverse Harm. Energy 160 | 161 | /* POWER & P.F. REGISTERS */ 162 | #define PmeanT 0xB0 // Total Mean Power (P) 163 | #define PmeanA 0xB1 // A Mean Power (P) 164 | #define PmeanB 0xB2 // B Mean Power (P) 165 | #define PmeanC 0xB3 // C Mean Power (P) 166 | #define QmeanT 0xB4 // Total Mean Power (Q) 167 | #define QmeanA 0xB5 // A Mean Power (Q) 168 | #define QmeanB 0xB6 // B Mean Power (Q) 169 | #define QmeanC 0xB7 // C Mean Power (Q) 170 | #define SmeanT 0xB8 // Total Mean Power (S) 171 | #define SmeanA 0xB9 // A Mean Power (S) 172 | #define SmeanB 0xBA // B Mean Power (S) 173 | #define SmeanC 0xBB // C Mean Power (S) 174 | #define PFmeanT 0xBC // Mean Power Factor 175 | #define PFmeanA 0xBD // A Power Factor 176 | #define PFmeanB 0xBE // B Power Factor 177 | #define PFmeanC 0xBF // C Power Factor 178 | 179 | #define PmeanTLSB 0xC0 // Lower Word (Tot. Act. Power) 180 | #define PmeanALSB 0xC1 // Lower Word (A Act. Power) 181 | #define PmeanBLSB 0xC2 // Lower Word (B Act. Power) 182 | #define PmeanCLSB 0xC3 // Lower Word (C Act. Power) 183 | #define QmeanTLSB 0xC4 // Lower Word (Tot. React. Power) 184 | #define QmeanALSB 0xC5 // Lower Word (A React. Power) 185 | #define QmeanBLSB 0xC6 // Lower Word (B React. Power) 186 | #define QmeanCLSB 0xC7 // Lower Word (C React. Power) 187 | #define SAmeanTLSB 0xC8 // Lower Word (Tot. App. Power) 188 | #define SmeanALSB 0xC9 // Lower Word (A App. Power) 189 | #define SmeanBLSB 0xCA // Lower Word (B App. Power) 190 | #define SmeanCLSB 0xCB // Lower Word (C App. Power) 191 | 192 | /* FUND/HARM POWER & V/I RMS REGISTERS */ 193 | #define PmeanTF 0xD0 // Total Active Fund. Power 194 | #define PmeanAF 0xD1 // A Active Fund. Power 195 | #define PmeanBF 0xD2 // B Active Fund. Power 196 | #define PmeanCF 0xD3 // C Active Fund. Power 197 | #define PmeanTH 0xD4 // Total Active Harm. Power 198 | #define PmeanAH 0xD5 // A Active Harm. Power 199 | #define PmeanBH 0xD6 // B Active Harm. Power 200 | #define PmeanCH 0xD7 // C Active Harm. Power 201 | #define UrmsA 0xD9 // A RMS Voltage 202 | #define UrmsB 0xDA // B RMS Voltage 203 | #define UrmsC 0xDB // C RMS Voltage 204 | #define IrmsN 0xDC // Calculated N RMS Current 205 | #define IrmsA 0xDD // A RMS Current 206 | #define IrmsB 0xDE // B RMS Current 207 | #define IrmsC 0xDF // C RMS Current 208 | 209 | #define PmeanTFLSB 0xE0 // Lower Word (Tot. Act. Fund. Power) 210 | #define PmeanAFLSB 0xE1 // Lower Word (A Act. Fund. Power) 211 | #define PmeanBFLSB 0xE2 // Lower Word (B Act. Fund. Power) 212 | #define PmeanCFLSB 0xE3 // Lower Word (C Act. Fund. Power) 213 | #define PmeanTHLSB 0xE4 // Lower Word (Tot. Act. Harm. Power) 214 | #define PmeanAHLSB 0xE5 // Lower Word (A Act. Harm. Power) 215 | #define PmeanBHLSB 0xE6 // Lower Word (B Act. Harm. Power) 216 | #define PmeanCHLSB 0xE7 // Lower Word (C Act. Harm. Power) 217 | ///////////////// 0xE8 // Reserved Register 218 | #define UrmsALSB 0xE9 // Lower Word (A RMS Voltage) 219 | #define UrmsBLSB 0xEA // Lower Word (B RMS Voltage) 220 | #define UrmsCLSB 0xEB // Lower Word (C RMS Voltage) 221 | ///////////////// 0xEC // Reserved Register 222 | #define IrmsALSB 0xED // Lower Word (A RMS Current) 223 | #define IrmsBLSB 0xEE // Lower Word (B RMS Current) 224 | #define IrmsCLSB 0xEF // Lower Word (C RMS Current) 225 | 226 | /* PEAK, FREQUENCY, ANGLE & TEMP REGISTERS*/ 227 | #define UPeakA 0xF1 // A Voltage Peak - THD+N on ATM90E36 228 | #define UPeakB 0xF2 // B Voltage Peak 229 | #define UPeakC 0xF3 // C Voltage Peak 230 | ///////////////// 0xF4 // Reserved Register 231 | #define IPeakA 0xF5 // A Current Peak 232 | #define IPeakB 0xF6 // B Current Peak 233 | #define IPeakC 0xF7 // C Current Peak 234 | #define Freq 0xF8 // Frequency 235 | #define PAngleA 0xF9 // A Mean Phase Angle 236 | #define PAngleB 0xFA // B Mean Phase Angle 237 | #define PAngleC 0xFB // C Mean Phase Angle 238 | #define Temp 0xFC // Measured Temperature 239 | #define UangleA 0xFD // A Voltage Phase Angle 240 | #define UangleB 0xFE // B Voltage Phase Angle 241 | #define UangleC 0xFF // C Voltage Phase Angle 242 | 243 | class ATM90E32 244 | { 245 | private: 246 | unsigned short CommEnergyIC(unsigned char RW, unsigned short address, unsigned short val); 247 | int _cs; 248 | unsigned short _lineFreq; 249 | unsigned short _pgagain; 250 | unsigned short _ugain; 251 | unsigned short _igainA; 252 | unsigned short _igainB; 253 | unsigned short _igainC; 254 | 255 | int Read32Register(signed short regh_addr, signed short regl_addr); 256 | 257 | public: 258 | /* Construct */ 259 | ATM90E32(void); 260 | /* Destruct */ 261 | ~ATM90E32(void); 262 | 263 | /* Initialization Functions */ 264 | void begin(int pin, unsigned short lineFreq, unsigned short pgagain, unsigned short ugain, unsigned short igainA, unsigned short igainB, unsigned short igainC); 265 | 266 | double CalculateVIOffset(unsigned short regh_addr, unsigned short regl_addr/*, unsigned short offset_reg*/); 267 | double CalculatePowerOffset(unsigned short regh_addr, unsigned short regl_addr/*, unsigned short offset_reg*/); 268 | double CalibrateVI(unsigned short reg, unsigned short actualVal); 269 | 270 | /* Main Electrical Parameters (GET)*/ 271 | double GetLineVoltageA(); 272 | double GetLineVoltageB(); 273 | double GetLineVoltageC(); 274 | 275 | double GetLineCurrentA(); 276 | double GetLineCurrentB(); 277 | double GetLineCurrentC(); 278 | double GetLineCurrentN(); 279 | 280 | double GetActivePowerA(); 281 | double GetActivePowerB(); 282 | double GetActivePowerC(); 283 | double GetTotalActivePower(); 284 | 285 | double GetTotalActiveFundPower(); 286 | double GetTotalActiveHarPower(); 287 | 288 | double GetReactivePowerA(); 289 | double GetReactivePowerB(); 290 | double GetReactivePowerC(); 291 | double GetTotalReactivePower(); 292 | 293 | double GetApparentPowerA(); 294 | double GetApparentPowerB(); 295 | double GetApparentPowerC(); 296 | double GetTotalApparentPower(); 297 | 298 | double GetFrequency(); 299 | 300 | double GetPowerFactorA(); 301 | double GetPowerFactorB(); 302 | double GetPowerFactorC(); 303 | double GetTotalPowerFactor(); 304 | 305 | double GetPhaseA(); 306 | double GetPhaseB(); 307 | double GetPhaseC(); 308 | 309 | double GetTemperature(); 310 | 311 | /* Gain Parameters (GET)*/ 312 | double GetValueRegister(unsigned short registerRead); 313 | 314 | /* Energy Consumption */ 315 | double GetImportEnergy(); 316 | double GetImportReactiveEnergy(); 317 | double GetImportApparentEnergy(); 318 | double GetExportEnergy(); 319 | double GetExportReactiveEnergy(); 320 | 321 | /* System Status */ 322 | unsigned short GetSysStatus0(); 323 | unsigned short GetSysStatus1(); 324 | unsigned short GetMeterStatus0(); 325 | unsigned short GetMeterStatus1(); 326 | }; 327 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ATM90E32 Arduino Library 2 | 3 | This library powers the [CircuitSetup Split Single Phase Energy Meter](https://github.com/CircuitSetup/Split-Single-Phase-Energy-Meter) and the [6 Channel Expandable Energy Meter](https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter). 4 | 5 | ## Use 6 | 7 | ### Setup 8 | ```cpp 9 | #include 10 | ATM90E32 energy_meter{}; 11 | 12 | void setup() { 13 | energy_meter.begin(CS_pin, lineFreq, PGAGain, VoltageGain, CurrentGainCT1, CurrentGainCT2, CurrentGainCT3); 14 | } 15 | ``` 16 | ### Getting Basic Power Data 17 | A loop to get basic power data: 18 | ```cpp 19 | void loop() { 20 | voltage1 = energy_meter.GetLineVoltageA(); 21 | voltage2 = energy_meter.GetLineVoltageB(); 22 | voltage3 = energy_meter.GetLineVoltageC(); 23 | 24 | CT1 = energy_meter.GetLineCurrentA(); 25 | CT2 = energy_meter.GetLineCurrentB(); 26 | CT3 = energy_meter.GetLineCurrentC(); 27 | 28 | watts1 = energy_meter.GetActivePowerA(); 29 | watts2 = energy_meter.GetActivePowerB(); 30 | watts3 = energy_meter.GetActivePowerC(); 31 | totalWatts = energy_meter.GetTotalActivePower(); 32 | } 33 | ``` 34 | ### Getting Metering Values 35 | The following are other functions for other metering data that the ATM90E32 calculates. 36 | - GetReactivePowerA() 37 | - GetReactivePowerB() 38 | - GetReactivePowerC() 39 | - GetTotalReactivePower() 40 | - GetApparentPowerA() 41 | - GetApparentPowerB() 42 | - GetApparentPowerC() 43 | - GetTotalApparentPower() 44 | - GetPowerFactorA() 45 | - GetPowerFactorB() 46 | - GetPowerFactorC() 47 | - GetTotalPowerFactor() 48 | - GetPhaseA() //phase angle 49 | - GetPhaseB() 50 | - GetPhaseC() 51 | - GetTotalActiveFundPower() 52 | - GetTotalActiveHarPower() 53 | - GetFrequency() //voltage frequency 54 | - GetTemperature() //chip temperature 55 | 56 | ### Getting Energy Over Time 57 | The following functions get data from the ATM90E32 that is converted to kWh. The registers are cleared once they are read. 58 | - GetImportEnergy() //forward active energy 59 | - GetImportReactiveEnergy() 60 | - GetImportApparentEnergy() 61 | - GetExportEnergy() //reverse active energy 62 | - GetExportReactiveEnergy() 63 | 64 | ### System Status 65 | These functions get the raw hex values from the system status registers 66 | - GetSysStatus0() 67 | - GetSysStatus1() 68 | - GetMeterStatus0() 69 | - GetMeterStatus1() 70 | 71 | ### Getting Any Other Register Value 72 | This function takes the name of any register (defined in ATM90E32.h) and outputs the value 73 | - GetValueRegister(registerRead) 74 | 75 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ATM90E32", 3 | "keywords": "energy meter, circuitsetup, spi, sensor, iot", 4 | "description": "Arduino library for energy meters that use the ATM90E32AS IC from Microchip/Atmel", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/CircuitSetup/ATM90E32.git" 8 | }, 9 | "version": "1.1.0", 10 | "authors": 11 | [ 12 | { 13 | "name": "Tisham Dhar", 14 | "url": "http://whatnicklife.blogspot.com/" 15 | }, 16 | { 17 | "name": "John deGlavina", 18 | "url": "https://circuitsetup.us", 19 | "maintainer": true 20 | } 21 | ], 22 | "frameworks": "arduino", 23 | "platforms": ["espressif8266", "espressif32", "atmelsam", "atmelmegaavr", "atmelavr"] 24 | } 25 | --------------------------------------------------------------------------------