2019-04-14 17:20:24 +01:00
/*
2019-10-27 10:13:24 +00:00
xnrg_07_ade7953 . ino - ADE7953 energy sensor support for Tasmota
2019-04-14 17:20:24 +01:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Theo Arends
2019-04-14 17:20:24 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2022-10-26 16:16:36 +01:00
# if defined(ESP32) && defined(USE_SPI)
# define USE_ESP32_SPI
# endif
# if defined(USE_I2C) || defined(USE_ESP32_SPI)
2019-04-14 17:20:24 +01:00
# ifdef USE_ENERGY_SENSOR
# ifdef USE_ADE7953
/*********************************************************************************************\
2023-01-28 10:30:42 +00:00
* ADE7953 - Energy used in Shelly 2.5 ( model 1 ) , EM ( model 2 ) , Plus 2 PM ( model 3 ) , Pro 1 PM ( model 4 ) , Pro 2 PM ( model 5 ) and Pro 4 PM ( model 6 )
2021-08-23 15:18:21 +01:00
*
* { " NAME " : " Shelly 2.5 " , " GPIO " : [ 320 , 0 , 32 , 0 , 224 , 193 , 0 , 0 , 640 , 192 , 608 , 225 , 3456 , 4736 ] , " FLAG " : 0 , " BASE " : 18 }
2022-10-12 16:18:27 +01:00
* { " NAME " : " Shelly EM " , " GPIO " : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 640 , 3457 , 608 , 224 , 8832 , 1 ] , " FLAG " : 0 , " BASE " : 18 }
2022-10-04 08:37:29 +01:00
* { " NAME " : " Shelly Plus 2PM PCB v0.1.5 " , " GPIO " : [ 320 , 0 , 192 , 0 , 0 , 0 , 1 , 1 , 225 , 224 , 0 , 0 , 0 , 0 , 193 , 0 , 0 , 0 , 0 , 0 , 0 , 608 , 3840 , 32 , 0 , 0 , 0 , 0 , 0 , 640 , 0 , 0 , 3458 , 4736 , 0 , 0 ] , " FLAG " : 0 , " BASE " : 1 , " CMND " : " AdcParam1 2,32000,40000,3350 " }
* { " NAME " : " Shelly Plus 2PM PCB v0.1.9 " , " GPIO " : [ 320 , 0 , 0 , 0 , 32 , 192 , 0 , 0 , 225 , 224 , 0 , 0 , 0 , 0 , 193 , 0 , 0 , 0 , 0 , 0 , 0 , 608 , 640 , 3458 , 0 , 0 , 0 , 0 , 0 , 9472 , 0 , 4736 , 0 , 0 , 0 , 0 ] , " FLAG " : 0 , " BASE " : 1 , " CMND " : " AdcParam1 2,10000,10000,3350 " }
2023-01-28 10:30:42 +00:00
* { " NAME " : " Shelly Pro 1PM " , " GPIO " : [ 9568 , 1 , 9472 , 1 , 768 , 0 , 0 , 0 , 672 , 704 , 736 , 0 , 0 , 0 , 5600 , 6214 , 0 , 0 , 0 , 5568 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3459 , 0 , 0 , 32 , 4736 , 0 , 160 , 0 ] , " FLAG " : 0 , " BASE " : 1 , " CMND " : " AdcParam1 2,5600,4700,3350 " }
* { " NAME " : " Shelly Pro 2PM " , " GPIO " : [ 9568 , 1 , 9472 , 1 , 768 , 0 , 0 , 0 , 672 , 704 , 736 , 9569 , 0 , 0 , 5600 , 6214 , 0 , 0 , 0 , 5568 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3460 , 0 , 0 , 32 , 4736 , 4737 , 160 , 161 ] , " FLAG " : 0 , " BASE " : 1 , " CMND " : " AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350 " }
2023-02-04 16:48:53 +00:00
* { " NAME " : " Shelly Pro 4PM " , " GPIO " : [ 0 , 6210 , 0 , 6214 , 9568 , 0 , 0 , 0 , 0 , 0 , 9569 , 0 , 768 , 0 , 5600 , 0 , 0 , 0 , 0 , 5568 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 736 , 704 , 3461 , 0 , 4736 , 0 , 0 , 672 ] , " FLAG " : 0 , " BASE " : 1 , " CMND " : " AdcParam1 2,5600,4700,3350 " }
2019-04-14 17:20:24 +01:00
*
* Based on datasheet from https : //www.analog.com/en/products/ade7953.html
*
2022-10-12 16:18:27 +01:00
* Model differences :
2023-01-21 13:30:35 +00:00
* Function Model1 Model2 Model3 Model4 Model5 Model6 Remark
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Shelly 2.5 EM Plus2PM Pro1PM Pro2PM Pro4PM
* Processor ESP8266 ESP8266 ESP32 ESP32 ESP32 ESP32
* Interface I2C I2C I2C SPI SPI SPI Interface type used
2023-02-08 13:14:49 +00:00
* Number of inputs 2 2 2 1 2 4 Count of ADE9753 inputs used
2023-01-21 13:30:35 +00:00
* Number of ADE9753 chips 1 1 1 1 2 2 Count of ADE9753 chips
* ADE9753 IRQ 1 2 3 4 5 6 Index defines model number
* Current measurement device shunt CT shunt shunt shunt shunt CT = Current Transformer
2023-02-08 13:14:49 +00:00
* Common voltage Yes Yes Yes No No Yes Show common voltage in GUI / JSON
* Common frequency Yes Yes Yes No No Yes Show common frequency in GUI / JSON
2023-01-21 13:30:35 +00:00
* Swapped channel A / B Yes No No No No No Defined by hardware design - Fixed by Tasmota
* Support Export Active No Yes No No No No Only EM supports correct negative value detection
* Show negative ( reactive ) power No Yes No No No No Only EM supports correct negative value detection
* Default phase calibration 0 200 0 0 0 0 CT needs different phase calibration than shunts
* Default reset pin on ESP8266 - 16 - - - - Legacy support . Replaced by GPIO ADE7953RST
2022-10-12 16:18:27 +01:00
*
2019-04-14 17:20:24 +01:00
* I2C Address : 0x38
2022-09-13 14:35:09 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Optionally allowing users to tweak calibration registers :
* - In addition to possible rules add a rule containing the calib . dat string like :
* - rule3 on file # calib . dat do { " angles " : { " angle0 " : 180 , " angle1 " : 176 } } endon
2022-10-05 14:17:54 +01:00
* - rule3 on file # calib . dat do { " rms " : { " current_a " : 4194303 , " current_b " : 4194303 , " voltage " : 1613194 } , " angles " : { " angle0 " : 200 , " angle1 " : 200 } , " powers " : { " totactive " : { " a " : 2723574 , " b " : 2723574 } , " apparent " : { " a " : 2723574 , " b " : 2723574 } , " reactive " : { " a " : 2723574 , " b " : 2723574 } } } endon
2022-09-13 14:35:09 +01:00
* - Restart Tasmota and obeserve that the results seem calibrated as Tasmota now uses the information from calib . dat
* To restore standard calibration using commands like VoltSet remove above entry from rule3
2019-04-14 17:20:24 +01:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-05 14:17:54 +01:00
# define XNRG_07 7
# define XI2C_07 7 // See I2CDEVICES.md
2019-04-14 17:20:24 +01:00
2022-10-05 14:17:54 +01:00
# define ADE7953_ADDR 0x38
2022-09-13 14:35:09 +01:00
/*********************************************************************************************/
2022-10-30 11:20:56 +00:00
# define ADE7953_ACCU_ENERGY // Use accumulating energy instead of instant power
2022-09-30 11:39:03 +01:00
//#define ADE7953_DUMP_REGS
2022-09-13 14:35:09 +01:00
2022-10-05 14:17:54 +01:00
# define ADE7953_PREF 1540 // 4194304 / (1540 / 1000) = 2723574 (= WGAIN, VAGAIN and VARGAIN)
# define ADE7953_UREF 26000 // 4194304 / (26000 / 10000) = 1613194 (= VGAIN)
# define ADE7953_IREF 10000 // 4194304 / (10000 / 10000) = 4194303 (= IGAIN, needs to be different than 4194304 in order to use calib.dat)
2019-04-14 17:20:24 +01:00
2022-09-13 14:35:09 +01:00
// Default calibration parameters can be overridden by a rule as documented above.
2022-10-05 14:17:54 +01:00
# define ADE7953_GAIN_DEFAULT 4194304 // = 0x400000 range 2097152 (min) to 6291456 (max)
# define ADE7953_PHCAL_DEFAULT 0 // = range -383 to 383 - Default phase calibration for Shunts
# define ADE7953_PHCAL_DEFAULT_CT 200 // = range -383 to 383 - Default phase calibration for Current Transformers (Shelly EM)
2022-09-13 16:58:22 +01:00
2023-01-27 14:53:40 +00:00
# define ADE7953_MAX_CHANNEL 4
2023-01-21 13:30:35 +00:00
enum Ade7953Models { ADE7953_SHELLY_25 , ADE7953_SHELLY_EM , ADE7953_SHELLY_PLUS_2PM , ADE7953_SHELLY_PRO_1PM , ADE7953_SHELLY_PRO_2PM , ADE7953_SHELLY_PRO_4PM } ;
2022-09-13 14:35:09 +01:00
2022-09-30 11:39:03 +01:00
enum Ade7953_8BitRegisters {
// Register Name Addres R/W Bt Ty Default Description
// ---------------------------- ------ --- -- -- ---------- --------------------------------------------------------------------
ADE7953_SAGCYC = 0x000 , // 0x000 R/W 8 U 0x00 Sag line cycles
ADE7953_DISNOLOAD , // 0x001 R/W 8 U 0x00 No-load detection disable (see Table 16)
ADE7953_RESERVED_0X002 , // 0x002
ADE7953_RESERVED_0X003 , // 0x003
ADE7953_LCYCMODE , // 0x004 R/W 8 U 0x40 Line cycle accumulation mode configuration (see Table 17)
ADE7953_RESERVED_0X005 , // 0x005
ADE7953_RESERVED_0X006 , // 0x006
ADE7953_PGA_V , // 0x007 R/W 8 U 0x00 Voltage channel gain configuration (Bits[2:0])
ADE7953_PGA_IA , // 0x008 R/W 8 U 0x00 Current Channel A gain configuration (Bits[2:0])
ADE7953_PGA_IB // 0x009 R/W 8 U 0x00 Current Channel B gain configuration (Bits[2:0])
} ;
2022-09-13 14:35:09 +01:00
enum Ade7953_16BitRegisters {
// Register Name Addres R/W Bt Ty Default Description
// ---------------------------- ------ --- -- -- ---------- --------------------------------------------------------------------
ADE7953_ZXTOUT = 0x100 , // 0x100 R/W 16 U 0xFFFF Zero-crossing timeout
ADE7953_LINECYC , // 0x101 R/W 16 U 0x0000 Number of half line cycles for line cycle energy accumulation mode
ADE7953_CONFIG , // 0x102 R/W 16 U 0x8004 Configuration register (see Table 18)
ADE7953_CF1DEN , // 0x103 R/W 16 U 0x003F CF1 frequency divider denominator. When modifying this register, two sequential write operations must be performed to ensure that the write is successful.
ADE7953_CF2DEN , // 0x104 R/W 16 U 0x003F CF2 frequency divider denominator. When modifying this register, two sequential write operations must be performed to ensure that the write is successful.
2022-09-24 17:49:41 +01:00
ADE7953_RESERVED_0X105 , // 0x105
ADE7953_RESERVED_0X106 , // 0x106
ADE7953_CFMODE , // 0x107 R/W 16 U 0x0300 CF output selection (see Table 19)
2022-09-13 14:35:09 +01:00
ADE7943_PHCALA , // 0x108 R/W 16 S 0x0000 Phase calibration register (Current Channel A). This register is in sign magnitude format.
ADE7943_PHCALB , // 0x109 R/W 16 S 0x0000 Phase calibration register (Current Channel B). This register is in sign magnitude format.
ADE7943_PFA , // 0x10A R 16 S 0x0000 Power factor (Current Channel A)
ADE7943_PFB , // 0x10B R 16 S 0x0000 Power factor (Current Channel B)
ADE7943_ANGLE_A , // 0x10C R 16 S 0x0000 Angle between the voltage input and the Current Channel A input
ADE7943_ANGLE_B , // 0x10D R 16 S 0x0000 Angle between the voltage input and the Current Channel B input
ADE7943_Period // 0x10E R 16 U 0x0000 Period register
} ;
enum Ade7953_32BitRegisters {
2022-09-24 17:49:41 +01:00
// Register Name Addres R/W Bt Ty Default Description
// ---------------------------- ------ --- -- -- ---------- --------------------------------------------------------------------
2022-09-13 14:35:09 +01:00
ADE7953_ACCMODE = 0x301 , // 0x301 R/W 24 U 0x000000 Accumulation mode (see Table 21)
2022-09-24 17:49:41 +01:00
2022-09-13 14:35:09 +01:00
ADE7953_AVA = 0x310 , // 0x310 R 24 S 0x000000 Instantaneous apparent power (Current Channel A)
ADE7953_BVA , // 0x311 R 24 S 0x000000 Instantaneous apparent power (Current Channel B)
ADE7953_AWATT , // 0x312 R 24 S 0x000000 Instantaneous active power (Current Channel A)
ADE7953_BWATT , // 0x313 R 24 S 0x000000 Instantaneous active power (Current Channel B)
ADE7953_AVAR , // 0x314 R 24 S 0x000000 Instantaneous reactive power (Current Channel A)
ADE7953_BVAR , // 0x315 R 24 S 0x000000 Instantaneous reactive power (Current Channel B)
ADE7953_IA , // 0x316 R 24 S 0x000000 Instantaneous current (Current Channel A)
ADE7953_IB , // 0x317 R 24 S 0x000000 Instantaneous current (Current Channel B)
ADE7953_V , // 0x318 R 24 S 0x000000 Instantaneous voltage (voltage channel)
2022-09-24 17:49:41 +01:00
ADE7953_RESERVED_0X319 , // 0x319
ADE7953_IRMSA , // 0x31A R 24 U 0x000000 IRMS register (Current Channel A)
2022-09-13 14:35:09 +01:00
ADE7953_IRMSB , // 0x31B R 24 U 0x000000 IRMS register (Current Channel B)
ADE7953_VRMS , // 0x31C R 24 U 0x000000 VRMS register
2022-09-24 17:49:41 +01:00
ADE7953_RESERVED_0X31D , // 0x31D
ADE7953_AENERGYA , // 0x31E R 24 S 0x000000 Active energy (Current Channel A)
2022-09-13 14:35:09 +01:00
ADE7953_AENERGYB , // 0x31F R 24 S 0x000000 Active energy (Current Channel B)
ADE7953_RENERGYA , // 0x320 R 24 S 0x000000 Reactive energy (Current Channel A)
ADE7953_RENERGYB , // 0x321 R 24 S 0x000000 Reactive energy (Current Channel B)
ADE7953_APENERGYA , // 0x322 R 24 S 0x000000 Apparent energy (Current Channel A)
ADE7953_APENERGYB , // 0x323 R 24 S 0x000000 Apparent energy (Current Channel B)
ADE7953_OVLVL , // 0x324 R/W 24 U 0xFFFFFF Overvoltage level
ADE7953_OILVL , // 0x325 R/W 24 U 0xFFFFFF Overcurrent level
ADE7953_VPEAK , // 0x326 R 24 U 0x000000 Voltage channel peak
ADE7953_RSTVPEAK , // 0x327 R 24 U 0x000000 Read voltage peak with reset
ADE7953_IAPEAK , // 0x328 R 24 U 0x000000 Current Channel A peak
ADE7953_RSTIAPEAK , // 0x329 R 24 U 0x000000 Read Current Channel A peak with reset
ADE7953_IBPEAK , // 0x32A R 24 U 0x000000 Current Channel B peak
ADE7953_RSTIBPEAK , // 0x32B R 24 U 0x000000 Read Current Channel B peak with reset
ADE7953_IRQENA , // 0x32C R/W 24 U 0x100000 Interrupt enable (Current Channel A, see Table 22)
ADE7953_IRQSTATA , // 0x32D R 24 U 0x000000 Interrupt status (Current Channel A, see Table 23)
ADE7953_RSTIRQSTATA , // 0x32E R 24 U 0x000000 Reset interrupt status (Current Channel A)
ADE7953_IRQENB , // 0x32F R/W 24 U 0x000000 Interrupt enable (Current Channel B, see Table 24)
ADE7953_IRQSTATB , // 0x330 R 24 U 0x000000 Interrupt status (Current Channel B, see Table 25)
ADE7953_RSTIRQSTATB , // 0x331 R 24 U 0x000000 Reset interrupt status (Current Channel B)
2022-09-24 17:49:41 +01:00
2022-09-13 14:35:09 +01:00
ADE7953_CRC = 0x37F , // 0x37F R 32 U 0xFFFFFFFF Checksum
ADE7953_AIGAIN , // 0x380 R/W 24 U 0x400000 Current channel gain (Current Channel A)
ADE7953_AVGAIN , // 0x381 R/W 24 U 0x400000 Voltage channel gain
ADE7953_AWGAIN , // 0x382 R/W 24 U 0x400000 Active power gain (Current Channel A)
ADE7953_AVARGAIN , // 0x383 R/W 24 U 0x400000 Reactive power gain (Current Channel A)
ADE7953_AVAGAIN , // 0x384 R/W 24 U 0x400000 Apparent power gain (Current Channel A)
2022-09-24 17:49:41 +01:00
ADE7953_RESERVED_0X385 , // 0x385
ADE7953_AIRMSOS , // 0x386 R/W 24 S 0x000000 IRMS offset (Current Channel A)
ADE7953_RESERVED_0X387 , // 0x387
ADE7953_VRMSOS , // 0x388 R/W 24 S 0x000000 VRMS offset
2022-09-13 14:35:09 +01:00
ADE7953_AWATTOS , // 0x389 R/W 24 S 0x000000 Active power offset correction (Current Channel A)
ADE7953_AVAROS , // 0x38A R/W 24 S 0x000000 Reactive power offset correction (Current Channel A)
ADE7953_AVAOS , // 0x38B R/W 24 S 0x000000 Apparent power offset correction (Current Channel A)
ADE7953_BIGAIN , // 0x38C R/W 24 U 0x400000 Current channel gain (Current Channel B)
ADE7953_BVGAIN , // 0x38D R/W 24 U 0x400000 This register should not be modified.
ADE7953_BWGAIN , // 0x38E R/W 24 U 0x400000 Active power gain (Current Channel B)
ADE7953_BVARGAIN , // 0x38F R/W 24 U 0x400000 Reactive power gain (Current Channel B)
ADE7953_BVAGAIN , // 0x390 R/W 24 U 0x400000 Apparent power gain (Current Channel B)
2022-09-24 17:49:41 +01:00
ADE7953_RESERVED_0X391 , // 0x391
ADE7953_BIRMSOS , // 0x392 R/W 24 S 0x000000 IRMS offset (Current Channel B)
ADE7953_RESERVED_0X393 , // 0x393
ADE7953_RESERVED_0X394 , // 0x394
ADE7953_BWATTOS , // 0x395 R/W 24 S 0x000000 Active power offset correction (Current Channel B)
2022-09-13 14:35:09 +01:00
ADE7953_BVAROS , // 0x396 R/W 24 S 0x000000 Reactive power offset correction (Current Channel B)
ADE7953_BVAOS // 0x397 R/W 24 S 0x000000 Apparent power offset correction (Current Channel B)
} ;
2022-09-13 16:58:22 +01:00
enum Ade7953CalibrationRegisters {
2022-10-26 16:16:36 +01:00
ADE7953_CAL_VGAIN ,
ADE7953_CAL_IGAIN ,
ADE7953_CAL_WGAIN ,
ADE7953_CAL_VAGAIN ,
ADE7953_CAL_VARGAIN ,
ADE7943_CAL_PHCAL
2022-09-13 16:58:22 +01:00
} ;
2022-10-26 16:16:36 +01:00
const uint8_t ADE7953_CALIBREGS = 6 ;
const uint16_t Ade7953CalibRegs [ 2 ] [ ADE7953_CALIBREGS ] {
{ ADE7953_AVGAIN , ADE7953_AIGAIN , ADE7953_AWGAIN , ADE7953_AVAGAIN , ADE7953_AVARGAIN , ADE7943_PHCALA } ,
{ ADE7953_BVGAIN , ADE7953_BIGAIN , ADE7953_BWGAIN , ADE7953_BVAGAIN , ADE7953_BVARGAIN , ADE7943_PHCALB }
2022-09-13 16:58:22 +01:00
} ;
2019-04-14 17:20:24 +01:00
2022-10-26 16:16:36 +01:00
const uint8_t ADE7953_REGISTERS = 6 ;
const uint16_t Ade7953Registers [ 2 ] [ ADE7953_REGISTERS ] {
2022-10-30 11:20:56 +00:00
# ifdef ADE7953_ACCU_ENERGY
{ ADE7953_IRMSA , ADE7953_AENERGYA , ADE7953_APENERGYA , ADE7953_RENERGYA , ADE7953_VRMS , ADE7943_Period } ,
{ ADE7953_IRMSB , ADE7953_AENERGYB , ADE7953_APENERGYB , ADE7953_RENERGYB , ADE7953_VRMS , ADE7943_Period }
# else // No ADE7953_ACCU_ENERGY
2022-10-26 16:16:36 +01:00
{ ADE7953_IRMSA , ADE7953_AWATT , ADE7953_AVA , ADE7953_AVAR , ADE7953_VRMS , ADE7943_Period } ,
{ ADE7953_IRMSB , ADE7953_BWATT , ADE7953_BVA , ADE7953_BVAR , ADE7953_VRMS , ADE7943_Period }
2022-10-30 11:20:56 +00:00
# endif // ADE7953_ACCU_ENERGY
2022-09-24 18:02:24 +01:00
} ;
2022-10-30 11:20:56 +00:00
# ifdef ADE7953_ACCU_ENERGY
const float ADE7953_LSB_PER_WATTSECOND = 2.5 ;
const float ADE7953_POWER_CORRECTION = 23.41494 ; // See https://github.com/arendst/Tasmota/pull/16941
# else // No ADE7953_ACCU_ENERGY
const float ADE7953_LSB_PER_WATTSECOND = 44 ;
# endif // ADE7953_ACCU_ENERGY
2023-01-26 16:27:49 +00:00
typedef struct {
uint32_t voltage_rms ;
uint32_t current_rms ;
uint32_t active_power ;
int32_t calib_data [ ADE7953_CALIBREGS ] ;
} tAde7953Channel ;
2019-08-16 13:41:02 +01:00
struct Ade7953 {
2023-02-20 17:02:43 +00:00
uint32_t last_update ;
2023-01-27 14:53:40 +00:00
uint32_t voltage_rms [ ADE7953_MAX_CHANNEL ] = { 0 , 0 } ;
uint32_t current_rms [ ADE7953_MAX_CHANNEL ] = { 0 , 0 } ;
uint32_t active_power [ ADE7953_MAX_CHANNEL ] = { 0 , 0 } ;
int32_t calib_data [ ADE7953_MAX_CHANNEL ] [ ADE7953_CALIBREGS ] ;
2019-08-16 13:41:02 +01:00
uint8_t init_step = 0 ;
2023-01-21 13:30:35 +00:00
uint8_t model = 0 ; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM, 3 = Shelly Pro 1PM, 4 = Shelly Pro 2PM, 5 = Shelly Pro 4PM
2022-10-26 16:16:36 +01:00
uint8_t cs_index ;
# ifdef USE_ESP32_SPI
2023-01-27 14:53:40 +00:00
int8_t pin_cs [ ADE7953_MAX_CHANNEL / 2 ] ;
2022-10-26 16:16:36 +01:00
# endif // USE_ESP32_SPI
2023-02-04 16:48:53 +00:00
bool use_spi ;
2019-08-16 13:41:02 +01:00
} Ade7953 ;
2019-04-14 17:20:24 +01:00
2023-01-21 13:30:35 +00:00
/*********************************************************************************************/
2022-09-13 14:35:09 +01:00
int Ade7953RegSize ( uint16_t reg ) {
2019-04-14 17:20:24 +01:00
int size = 0 ;
switch ( ( reg > > 8 ) & 0x0F ) {
2022-09-13 14:35:09 +01:00
case 0x03 : // 32-bit
2019-04-14 17:20:24 +01:00
size + + ;
2022-09-13 14:35:09 +01:00
case 0x02 : // 24-bit
2019-04-14 17:20:24 +01:00
size + + ;
2022-09-13 14:35:09 +01:00
case 0x01 : // 16-bit
2019-04-14 17:20:24 +01:00
size + + ;
2022-09-13 14:35:09 +01:00
case 0x00 : // 8-bit
2019-04-14 17:20:24 +01:00
case 0x07 :
case 0x08 :
size + + ;
}
return size ;
}
2023-01-21 14:42:31 +00:00
# ifdef USE_ESP32_SPI
2023-01-21 13:30:35 +00:00
void Ade7953SpiEnable ( void ) {
digitalWrite ( Ade7953 . pin_cs [ Ade7953 . cs_index ] , 0 ) ;
delayMicroseconds ( 1 ) ; // CS 1uS to SCLK edge
SPI . beginTransaction ( SPISettings ( 1000000 , MSBFIRST , SPI_MODE0 ) ) ; // Set up SPI at 1MHz, MSB first, Capture at rising edge
}
void Ade7953SpiDisable ( void ) {
SPI . endTransaction ( ) ;
delayMicroseconds ( 2 ) ; // CS high 1.2uS after SCLK edge (when writing to COMM_LOCK bit)
digitalWrite ( Ade7953 . pin_cs [ Ade7953 . cs_index ] , 1 ) ;
}
2023-01-21 14:42:31 +00:00
# endif // USE_ESP32_SPI
2023-01-21 13:30:35 +00:00
2022-09-13 14:35:09 +01:00
void Ade7953Write ( uint16_t reg , uint32_t val ) {
2019-04-14 17:20:24 +01:00
int size = Ade7953RegSize ( reg ) ;
if ( size ) {
2022-10-26 16:16:36 +01:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Write %08X"), val);
# ifdef USE_ESP32_SPI
2023-02-04 16:48:53 +00:00
if ( Ade7953 . use_spi ) {
2023-01-21 13:30:35 +00:00
Ade7953SpiEnable ( ) ;
SPI . transfer16 ( reg ) ;
SPI . transfer ( 0x00 ) ; // Write
while ( size - - ) {
SPI . transfer ( ( val > > ( 8 * size ) ) & 0xFF ) ; // Write data, MSB first
}
Ade7953SpiDisable ( ) ;
2022-10-26 16:16:36 +01:00
} else {
# endif // USE_ESP32_SPI
Wire . beginTransmission ( ADE7953_ADDR ) ;
Wire . write ( ( reg > > 8 ) & 0xFF ) ;
Wire . write ( reg & 0xFF ) ;
while ( size - - ) {
Wire . write ( ( val > > ( 8 * size ) ) & 0xFF ) ; // Write data, MSB first
}
Wire . endTransmission ( ) ;
delayMicroseconds ( 5 ) ; // Bus-free time minimum 4.7us
# ifdef USE_ESP32_SPI
2019-04-14 17:20:24 +01:00
}
2022-10-26 16:16:36 +01:00
# endif // USE_ESP32_SPI
2019-04-14 17:20:24 +01:00
}
}
2022-09-13 14:35:09 +01:00
int32_t Ade7953Read ( uint16_t reg ) {
2022-10-30 11:20:56 +00:00
uint32_t response = 0 ;
2019-04-14 17:20:24 +01:00
int size = Ade7953RegSize ( reg ) ;
if ( size ) {
2022-10-26 16:16:36 +01:00
# ifdef USE_ESP32_SPI
2023-02-04 16:48:53 +00:00
if ( Ade7953 . use_spi ) {
2023-01-21 13:30:35 +00:00
Ade7953SpiEnable ( ) ;
SPI . transfer16 ( reg ) ;
SPI . transfer ( 0x80 ) ; // Read
while ( size - - ) {
response = response < < 8 | SPI . transfer ( 0xFF ) ; // receive DATA (MSB first)
}
Ade7953SpiDisable ( ) ;
2022-10-26 16:16:36 +01:00
} else {
# endif // USE_ESP32_SPI
Wire . beginTransmission ( ADE7953_ADDR ) ;
Wire . write ( ( reg > > 8 ) & 0xFF ) ;
Wire . write ( reg & 0xFF ) ;
Wire . endTransmission ( 0 ) ;
Wire . requestFrom ( ADE7953_ADDR , size ) ;
if ( size < = Wire . available ( ) ) {
for ( uint32_t i = 0 ; i < size ; i + + ) {
response = response < < 8 | Wire . read ( ) ; // receive DATA (MSB first)
}
2019-04-14 17:20:24 +01:00
}
2022-10-26 16:16:36 +01:00
# ifdef USE_ESP32_SPI
2019-04-14 17:20:24 +01:00
}
2022-10-26 16:16:36 +01:00
# endif // USE_ESP32_SPI
2019-04-14 17:20:24 +01:00
}
2022-10-30 11:20:56 +00:00
return response ;
2019-04-14 17:20:24 +01:00
}
2022-09-30 11:39:03 +01:00
# ifdef ADE7953_DUMP_REGS
2023-02-09 13:46:54 +00:00
void Ade7953DumpRegs ( uint32_t chip ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: *** Chip%d **** SAGCYC DISNOLD Resrvd Resrvd LCYCMOD Resrvd Resrvd PGAV PGAIA PGAIB " ) , chip + 1 ) ;
2022-09-30 17:01:34 +01:00
char data [ 200 ] = { 0 } ;
2022-09-30 11:39:03 +01:00
for ( uint32_t i = 0 ; i < 10 ; i + + ) {
int32_t value = Ade7953Read ( ADE7953_SAGCYC + i ) ;
2022-09-30 17:01:34 +01:00
snprintf_P ( data , sizeof ( data ) , PSTR ( " %s %02X " ) , data , value ) ; // 8-bit regs
2022-09-30 11:39:03 +01:00
}
2022-10-26 16:16:36 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: *** 0x000..009%s " ) , data ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: *** ZXTOUT LINECYC CONFIG CF1DEN CF2DEN Resrvd Resrvd CFMODE PHCALA PHCALB PFA PFB ANGLEA ANGLEB Period " ) ) ;
2022-09-30 11:39:03 +01:00
data [ 0 ] = ' \0 ' ;
for ( uint32_t i = 0 ; i < 15 ; i + + ) {
int32_t value = Ade7953Read ( ADE7953_ZXTOUT + i ) ;
2022-09-30 17:01:34 +01:00
snprintf_P ( data , sizeof ( data ) , PSTR ( " %s %04X " ) , data , value ) ; // 16-bit regs
2022-09-30 11:39:03 +01:00
}
2022-10-26 16:16:36 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: *** 0x100..10E%s " ) , data ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: *** IGAIN VGAIN WGAIN VARGAIN VAGAIN Resrvd IRMSOS Resrvd VRMSOS WATTOS VAROS VAOS " ) ) ;
2022-09-30 11:39:03 +01:00
data [ 0 ] = ' \0 ' ;
2022-09-30 17:01:34 +01:00
for ( uint32_t i = 0 ; i < 12 ; i + + ) {
2022-09-30 11:39:03 +01:00
int32_t value = Ade7953Read ( ADE7953_AIGAIN + i ) ;
2022-09-30 17:01:34 +01:00
snprintf_P ( data , sizeof ( data ) , PSTR ( " %s %06X " ) , data , value ) ; // 24-bit regs
2022-09-30 11:39:03 +01:00
}
2022-10-26 16:16:36 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: *** 0x380..38B%s " ) , data ) ;
2022-09-30 17:01:34 +01:00
data [ 0 ] = ' \0 ' ;
for ( uint32_t i = 0 ; i < 12 ; i + + ) {
int32_t value = Ade7953Read ( ADE7953_BIGAIN + i ) ;
snprintf_P ( data , sizeof ( data ) , PSTR ( " %s %06X " ) , data , value ) ; // 24-bit regs
}
2022-10-26 16:16:36 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: *** 0x38C..397%s " ) , data ) ;
2022-09-30 11:39:03 +01:00
}
# endif // ADE7953_DUMP_REGS
2022-10-26 16:16:36 +01:00
void Ade7953SetCalibration ( uint32_t regset , uint32_t calibset ) {
for ( uint32_t i = 0 ; i < ADE7953_CALIBREGS ; i + + ) {
int32_t value = Ade7953 . calib_data [ calibset ] [ i ] ;
if ( ADE7943_CAL_PHCAL = = i ) {
// if (ADE7953_PHCAL_DEFAULT == value) { continue; } // ADE7953 reset does NOT always reset all registers
if ( value < 0 ) {
value = abs ( value ) + 0x200 ; // Add sign magnitude
}
}
// if (ADE7953_GAIN_DEFAULT == value) { continue; } // ADE7953 reset does NOT always reset all registers
Ade7953Write ( Ade7953CalibRegs [ regset ] [ i ] , value ) ;
}
}
2022-09-13 14:35:09 +01:00
void Ade7953Init ( void ) {
2022-10-26 16:16:36 +01:00
uint32_t chips = 1 ;
# ifdef USE_ESP32_SPI
chips = ( Ade7953 . pin_cs [ 1 ] > = 0 ) ? 2 : 1 ;
# endif // USE_ESP32_SPI
2023-02-08 13:14:49 +00:00
// Init ADE7953 with calibration settings
2022-10-26 16:16:36 +01:00
for ( uint32_t chip = 0 ; chip < chips ; chip + + ) {
Ade7953 . cs_index = chip ;
2022-09-30 11:39:03 +01:00
# ifdef ADE7953_DUMP_REGS
2023-02-09 13:46:54 +00:00
Ade7953DumpRegs ( chip ) ;
2022-09-30 11:39:03 +01:00
# endif // ADE7953_DUMP_REGS
2022-10-26 16:16:36 +01:00
Ade7953Write ( ADE7953_CONFIG , 0x0004 ) ; // Locking the communication interface (Clear bit COMM_LOCK), Enable HPF
Ade7953Write ( 0x0FE , 0x00AD ) ; // Unlock register 0x120
Ade7953Write ( 0x120 , 0x0030 ) ; // Configure optimum setting
# ifdef USE_ESP32_SPI
2022-10-27 16:52:44 +01:00
// int32_t value = Ade7953Read(0x702); // Silicon version
// AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Chip%d version %d"), chip +1, value);
2023-02-08 13:14:49 +00:00
if ( 1 = = chip ) {
switch ( Ade7953 . model ) {
case ADE7953_SHELLY_PRO_2PM :
Ade7953SetCalibration ( 0 , 1 ) ; // Second ADE7953 A registers set with calibration set 1
break ;
case ADE7953_SHELLY_PRO_4PM :
Ade7953SetCalibration ( 0 , 2 ) ; // Second ADE7953 A registers set with calibration set 2
Ade7953SetCalibration ( 1 , 3 ) ; // Second ADE7953 B registers set with calibration set 3
}
} else {
2022-10-26 16:16:36 +01:00
# endif // USE_ESP32_SPI
2023-02-08 13:14:49 +00:00
Ade7953SetCalibration ( 0 , 0 ) ; // First ADE7953 A registers set with calibration set 0
switch ( Ade7953 . model ) {
case ADE7953_SHELLY_25 :
case ADE7953_SHELLY_EM :
case ADE7953_SHELLY_PLUS_2PM :
// case ADE7953_SHELLY_PRO_1PM: // Uses defaults for B registers
case ADE7953_SHELLY_PRO_4PM :
Ade7953SetCalibration ( 1 , 1 ) ; // First ADE7953 B registers set with calibration set 1
}
2022-10-26 16:16:36 +01:00
# ifdef USE_ESP32_SPI
2023-02-08 13:14:49 +00:00
}
2022-10-26 16:16:36 +01:00
# endif // USE_ESP32_SPI
2023-02-08 13:14:49 +00:00
}
2022-10-26 16:16:36 +01:00
2023-02-08 13:14:49 +00:00
// Report set calibration settings
2022-10-26 16:16:36 +01:00
int32_t regs [ ADE7953_CALIBREGS ] ;
for ( uint32_t chip = 0 ; chip < chips ; chip + + ) {
Ade7953 . cs_index = chip ;
for ( uint32_t channel = 0 ; channel < 2 ; channel + + ) {
for ( uint32_t i = 0 ; i < ADE7953_CALIBREGS ; i + + ) {
regs [ i ] = Ade7953Read ( Ade7953CalibRegs [ channel ] [ i ] ) ;
if ( ADE7943_CAL_PHCAL = = i ) {
if ( regs [ i ] > = 0x0200 ) {
regs [ i ] & = 0x01FF ; // Clear sign magnitude
regs [ i ] * = - 1 ; // Make negative
}
}
2022-09-24 17:49:41 +01:00
}
2022-10-26 16:16:36 +01:00
# ifdef USE_ESP32_SPI
2023-01-27 14:53:40 +00:00
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " ADE: Chip%d CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d " ) ,
chip + 1 , ' A ' + channel , regs [ 0 ] , regs [ 1 ] , regs [ 2 ] , regs [ 3 ] , regs [ 4 ] , regs [ 5 ] ) ;
2022-10-26 16:16:36 +01:00
# else
2023-01-27 14:53:40 +00:00
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " ADE: CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d " ) ,
' A ' + channel , regs [ 0 ] , regs [ 1 ] , regs [ 2 ] , regs [ 3 ] , regs [ 4 ] , regs [ 5 ] ) ;
2022-10-26 16:16:36 +01:00
# endif // USE_ESP32_SPI
2022-09-24 17:49:41 +01:00
}
2022-10-26 16:16:36 +01:00
2022-09-30 11:39:03 +01:00
# ifdef ADE7953_DUMP_REGS
2023-02-09 13:46:54 +00:00
Ade7953DumpRegs ( chip ) ;
2022-09-30 11:39:03 +01:00
# endif // ADE7953_DUMP_REGS
2022-10-26 16:16:36 +01:00
}
2019-04-14 17:20:24 +01:00
}
2022-09-13 14:35:09 +01:00
void Ade7953GetData ( void ) {
2022-10-26 16:16:36 +01:00
uint32_t acc_mode = 0 ;
2023-01-27 14:53:40 +00:00
int32_t reg [ ADE7953_MAX_CHANNEL ] [ ADE7953_REGISTERS ] ;
2022-10-26 16:16:36 +01:00
# ifdef USE_ESP32_SPI
2023-02-04 16:48:53 +00:00
if ( Ade7953 . use_spi ) {
2023-01-26 16:27:49 +00:00
uint32_t channel = 0 ;
2023-01-27 14:53:40 +00:00
for ( uint32_t chip = 0 ; chip < ADE7953_MAX_CHANNEL / 2 ; chip + + ) {
2022-10-26 16:16:36 +01:00
if ( Ade7953 . pin_cs [ chip ] < 0 ) { continue ; }
Ade7953 . cs_index = chip ;
for ( uint32_t i = 0 ; i < ADE7953_REGISTERS ; i + + ) {
2023-01-26 16:27:49 +00:00
reg [ channel ] [ i ] = Ade7953Read ( Ade7953Registers [ 0 ] [ i ] ) ; // IRMSa, WATTa, VAa, VARa, VRMS, Period
}
channel + + ;
if ( 4 = = Energy - > phase_count ) {
for ( uint32_t i = 0 ; i < ADE7953_REGISTERS ; i + + ) {
reg [ channel ] [ i ] = Ade7953Read ( Ade7953Registers [ 1 ] [ i ] ) ; // IRMSb, WATTb, VAb, VARb, VRMS, Period
}
channel + + ;
2022-10-26 16:16:36 +01:00
}
2019-09-15 12:10:32 +01:00
}
2022-10-26 16:16:36 +01:00
} else {
# endif // USE_ESP32_SPI
for ( uint32_t channel = 0 ; channel < 2 ; channel + + ) {
uint32_t channel_swap = ( ADE7953_SHELLY_25 = = Ade7953 . model ) ? ! channel : channel ;
for ( uint32_t i = 0 ; i < ADE7953_REGISTERS ; i + + ) {
reg [ channel_swap ] [ i ] = Ade7953Read ( Ade7953Registers [ channel ] [ i ] ) ;
}
}
acc_mode = Ade7953Read ( ADE7953_ACCMODE ) ; // Accumulation mode
# ifdef USE_ESP32_SPI
2019-04-14 17:20:24 +01:00
}
2022-10-26 16:16:36 +01:00
# endif // USE_ESP32_SPI
2023-01-21 13:30:35 +00:00
2023-01-26 16:27:49 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " ADE: Channel%d ACCMODE 0x%06X, VRMS %d, Period %d, IRMS %d, WATT %d, VA %d, VAR %d " ) ,
i + 1 , acc_mode , reg [ i ] [ 4 ] , reg [ i ] [ 5 ] , reg [ i ] [ 0 ] , reg [ i ] [ 1 ] , reg [ i ] [ 2 ] , reg [ i ] [ 3 ] ) ;
}
2019-09-15 12:10:32 +01:00
2022-10-30 11:20:56 +00:00
// If the device is initializing, we read the energy registers to reset them, but don't report the values as the first read may be inaccurate
if ( Ade7953 . init_step ) { return ; }
2023-01-27 14:53:40 +00:00
uint32_t apparent_power [ ADE7953_MAX_CHANNEL ] = { 0 , 0 } ;
uint32_t reactive_power [ ADE7953_MAX_CHANNEL ] = { 0 , 0 } ;
2019-09-15 12:10:32 +01:00
2023-01-24 15:54:03 +00:00
for ( uint32_t channel = 0 ; channel < Energy - > phase_count ; channel + + ) {
2022-10-26 16:16:36 +01:00
Ade7953 . voltage_rms [ channel ] = reg [ channel ] [ 4 ] ;
2019-09-15 12:10:32 +01:00
Ade7953 . current_rms [ channel ] = reg [ channel ] [ 0 ] ;
2022-10-26 16:16:36 +01:00
if ( Ade7953 . current_rms [ channel ] < 2000 ) { // No load threshold (20mA)
2019-09-15 12:10:32 +01:00
Ade7953 . current_rms [ channel ] = 0 ;
Ade7953 . active_power [ channel ] = 0 ;
} else {
Ade7953 . active_power [ channel ] = abs ( reg [ channel ] [ 1 ] ) ;
apparent_power [ channel ] = abs ( reg [ channel ] [ 2 ] ) ;
2022-10-13 11:58:59 +01:00
reactive_power [ channel ] = abs ( reg [ channel ] [ 3 ] ) ;
2022-10-13 14:48:23 +01:00
if ( ( ADE7953_SHELLY_EM = = Ade7953 . model ) & & ( bitRead ( acc_mode , 18 + ( channel * 3 ) ) ) ) { // VARNLOAD
2022-10-13 11:58:59 +01:00
reactive_power [ channel ] = 0 ;
2022-10-13 08:42:42 +01:00
}
2019-09-15 12:10:32 +01:00
}
2019-04-14 17:20:24 +01:00
}
2019-09-15 12:10:32 +01:00
2023-01-24 15:54:03 +00:00
if ( Energy - > power_on ) { // Powered on
2023-02-20 17:02:43 +00:00
2023-02-22 09:30:47 +00:00
# ifdef USE_ESP32_SPI
2023-02-20 17:02:43 +00:00
float correction = 1.0f ;
if ( Ade7953 . use_spi ) { // SPI
uint32_t time = millis ( ) ;
if ( Ade7953 . last_update ) {
uint32_t difference = time - Ade7953 . last_update ;
correction = ( float ) difference / 1000 ; // Correction to 1 second
// AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Correction %4_f"), &correction);
}
Ade7953 . last_update = time ;
}
2023-02-22 09:30:47 +00:00
# endif // USE_ESP32_SPI
2023-02-20 17:02:43 +00:00
2022-10-26 16:16:36 +01:00
float divider ;
2023-01-24 15:54:03 +00:00
for ( uint32_t channel = 0 ; channel < Energy - > phase_count ; channel + + ) {
Energy - > data_valid [ channel ] = 0 ;
2022-10-26 16:16:36 +01:00
2023-01-25 16:05:48 +00:00
float power_calibration = ( float ) EnergyGetCalibration ( ENERGY_POWER_CALIBRATION , channel ) / 10 ;
2022-10-30 11:20:56 +00:00
# ifdef ADE7953_ACCU_ENERGY
power_calibration / = ADE7953_POWER_CORRECTION ;
# endif // ADE7953_ACCU_ENERGY
2023-01-25 16:05:48 +00:00
float voltage_calibration = ( float ) EnergyGetCalibration ( ENERGY_VOLTAGE_CALIBRATION , channel ) ;
float current_calibration = ( float ) EnergyGetCalibration ( ENERGY_CURRENT_CALIBRATION , channel ) * 10 ;
2022-10-29 18:08:06 +01:00
2023-01-24 15:54:03 +00:00
Energy - > frequency [ channel ] = 223750.0f / ( ( float ) reg [ channel ] [ 5 ] + 1 ) ;
2023-01-26 16:27:49 +00:00
2022-10-29 18:08:06 +01:00
divider = ( Ade7953 . calib_data [ channel ] [ ADE7953_CAL_VGAIN ] ! = ADE7953_GAIN_DEFAULT ) ? 10000 : voltage_calibration ;
2023-01-24 15:54:03 +00:00
Energy - > voltage [ channel ] = ( float ) Ade7953 . voltage_rms [ channel ] / divider ;
2023-01-26 16:27:49 +00:00
divider = ( Ade7953 . calib_data [ channel ] [ ADE7953_CAL_WGAIN ] ! = ADE7953_GAIN_DEFAULT ) ? ADE7953_LSB_PER_WATTSECOND : power_calibration ;
2023-01-24 15:54:03 +00:00
Energy - > active_power [ channel ] = ( float ) Ade7953 . active_power [ channel ] / divider ;
2023-01-26 16:27:49 +00:00
divider = ( Ade7953 . calib_data [ channel ] [ ADE7953_CAL_VARGAIN ] ! = ADE7953_GAIN_DEFAULT ) ? ADE7953_LSB_PER_WATTSECOND : power_calibration ;
2023-01-24 15:54:03 +00:00
Energy - > reactive_power [ channel ] = ( float ) reactive_power [ channel ] / divider ;
2023-01-26 16:27:49 +00:00
2022-09-13 14:35:09 +01:00
if ( ADE7953_SHELLY_EM = = Ade7953 . model ) {
2022-10-26 16:16:36 +01:00
if ( bitRead ( acc_mode , 10 + channel ) ) { // APSIGN
2023-01-24 15:54:03 +00:00
Energy - > active_power [ channel ] * = - 1 ;
2021-08-23 15:18:21 +01:00
}
2022-10-26 16:16:36 +01:00
if ( bitRead ( acc_mode , 12 + channel ) ) { // VARSIGN
2023-01-24 15:54:03 +00:00
Energy - > reactive_power [ channel ] * = - 1 ;
2021-08-23 15:18:21 +01:00
}
2021-08-23 17:18:11 +01:00
}
2023-01-26 16:27:49 +00:00
divider = ( Ade7953 . calib_data [ channel ] [ ADE7953_CAL_VAGAIN ] ! = ADE7953_GAIN_DEFAULT ) ? ADE7953_LSB_PER_WATTSECOND : power_calibration ;
2023-01-24 15:54:03 +00:00
Energy - > apparent_power [ channel ] = ( float ) apparent_power [ channel ] / divider ;
2023-01-26 16:27:49 +00:00
2023-02-22 09:30:47 +00:00
# ifdef USE_ESP32_SPI
2023-02-20 17:02:43 +00:00
if ( Ade7953 . use_spi ) { // SPI
Energy - > active_power [ channel ] / = correction ;
Energy - > reactive_power [ channel ] / = correction ;
Energy - > apparent_power [ channel ] / = correction ;
}
2023-02-22 09:30:47 +00:00
# endif // USE_ESP32_SPI
2023-02-20 17:02:43 +00:00
2023-01-24 15:54:03 +00:00
if ( 0 = = Energy - > active_power [ channel ] ) {
Energy - > current [ channel ] = 0 ;
2019-09-15 12:10:32 +01:00
} else {
2023-01-26 16:27:49 +00:00
divider = ( Ade7953 . calib_data [ channel ] [ ADE7953_CAL_IGAIN ] ! = ADE7953_GAIN_DEFAULT ) ? 100000 : current_calibration ;
2023-01-24 15:54:03 +00:00
Energy - > current [ channel ] = ( float ) Ade7953 . current_rms [ channel ] / divider ;
Energy - > kWhtoday_delta [ channel ] + = Energy - > active_power [ channel ] * 1000 / 36 ;
2019-09-15 12:10:32 +01:00
}
2019-04-14 17:20:24 +01:00
}
2021-09-29 14:33:58 +01:00
EnergyUpdateToday ( ) ;
2019-04-14 17:20:24 +01:00
}
2019-06-21 13:31:08 +01:00
}
2022-09-13 14:35:09 +01:00
void Ade7953EnergyEverySecond ( void ) {
2022-10-30 11:20:56 +00:00
if ( Ade7953 . init_step ) {
if ( 2 = = Ade7953 . init_step ) { Ade7953Init ( ) ; }
if ( 1 = = Ade7953 . init_step ) { Ade7953GetData ( ) ; } // Read registers but do not display yet
2019-08-16 13:41:02 +01:00
Ade7953 . init_step - - ;
2022-10-30 11:20:56 +00:00
} else {
Ade7953GetData ( ) ;
}
2019-04-14 17:20:24 +01:00
}
2022-09-13 14:35:09 +01:00
/*********************************************************************************************/
bool Ade7953SetDefaults ( const char * json ) {
// {"angles":{"angle0":180,"angle1":176}}
2022-09-13 16:58:22 +01:00
// {"rms":{"current_a":4194303,"current_b":4194303,"voltage":1613194},"angles":{"angle0":0,"angle1":0},"powers":{"totactive":{"a":2723574,"b":2723574},"apparent":{"a":2723574,"b":2723574},"reactive":{"a":2723574,"b":2723574}}}
2022-10-26 16:16:36 +01:00
// {"rms":{"current_a":21865738,"current_b":1558533,"voltage_a":1599149,"voltage_b":1597289},"angles":{"angle0":0,"angle1":0},"powers":{"totactive":{"a":106692616,"b":3540894}}}
2022-09-13 14:35:09 +01:00
uint32_t len = strlen ( json ) + 1 ;
2022-10-26 16:16:36 +01:00
if ( len < 7 ) { return false ; } // Too short
2022-09-13 14:35:09 +01:00
char json_buffer [ len ] ;
2022-10-26 16:16:36 +01:00
memcpy ( json_buffer , json , len ) ; // Keep original safe
2022-09-13 14:35:09 +01:00
JsonParser parser ( json_buffer ) ;
JsonParserObject root = parser . getRootObject ( ) ;
if ( ! root ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " ADE: Invalid JSON " ) ) ;
return false ;
}
// All parameters are optional allowing for partial changes
JsonParserToken val ;
2023-01-27 14:53:40 +00:00
char field [ 20 ] ;
for ( uint32_t i = 0 ; i < ADE7953_MAX_CHANNEL ; i + + ) {
JsonParserObject rms = root [ PSTR ( " rms " ) ] . getObject ( ) ;
if ( rms ) {
val = rms [ PSTR ( " voltage " ) ] ;
if ( val ) {
Ade7953 . calib_data [ i ] [ ADE7953_CAL_VGAIN ] = val . getInt ( ) ;
}
# ifdef USE_ESP32_SPI
snprintf_P ( field , sizeof ( field ) , PSTR ( " voltage_%c " ) , ' a ' + i ) ;
val = rms [ field ] ; // "voltage_a" .. "voltage_d"
if ( val ) { Ade7953 . calib_data [ i ] [ ADE7953_CAL_VGAIN ] = val . getInt ( ) ; }
# endif // USE_ESP32_SPI
snprintf_P ( field , sizeof ( field ) , PSTR ( " current_%c " ) , ' a ' + i ) ;
val = rms [ field ] ; // "current_a" .. "current_d"
if ( val ) { Ade7953 . calib_data [ i ] [ ADE7953_CAL_IGAIN ] = val . getInt ( ) ; }
2022-09-13 14:35:09 +01:00
}
2023-01-27 14:53:40 +00:00
JsonParserObject angles = root [ PSTR ( " angles " ) ] . getObject ( ) ;
if ( angles ) {
snprintf_P ( field , sizeof ( field ) , PSTR ( " angle%c " ) , ' 0 ' + i ) ;
val = angles [ field ] ; // "angle0" .. "angle3"
if ( val ) { Ade7953 . calib_data [ i ] [ ADE7943_CAL_PHCAL ] = val . getInt ( ) ; }
2022-09-13 14:35:09 +01:00
}
2023-01-27 14:53:40 +00:00
JsonParserObject powers = root [ PSTR ( " powers " ) ] . getObject ( ) ;
if ( powers ) {
snprintf_P ( field , sizeof ( field ) , PSTR ( " %c " ) , ' a ' + i ) ;
JsonParserObject totactive = powers [ PSTR ( " totactive " ) ] . getObject ( ) ;
if ( totactive ) {
val = totactive [ field ] ; // "a" .. "d"
if ( val ) { Ade7953 . calib_data [ i ] [ ADE7953_CAL_WGAIN ] = val . getInt ( ) ; }
}
JsonParserObject apparent = powers [ PSTR ( " apparent " ) ] . getObject ( ) ;
if ( apparent ) {
val = apparent [ field ] ; // "a" .. "d"
if ( val ) { Ade7953 . calib_data [ i ] [ ADE7953_CAL_VAGAIN ] = val . getInt ( ) ; }
}
JsonParserObject reactive = powers [ PSTR ( " reactive " ) ] . getObject ( ) ;
if ( reactive ) {
val = reactive [ field ] ; // "a" .. "d"
if ( val ) { Ade7953 . calib_data [ i ] [ ADE7953_CAL_VARGAIN ] = val . getInt ( ) ; }
}
2022-09-13 14:35:09 +01:00
}
}
return true ;
}
void Ade7953Defaults ( void ) {
2023-01-27 14:53:40 +00:00
for ( uint32_t channel = 0 ; channel < ADE7953_MAX_CHANNEL ; channel + + ) {
2022-10-26 16:16:36 +01:00
for ( uint32_t i = 0 ; i < ADE7953_CALIBREGS ; i + + ) {
if ( ADE7943_CAL_PHCAL = = i ) {
Ade7953 . calib_data [ channel ] [ i ] = ( ADE7953_SHELLY_EM = = Ade7953 . model ) ? ADE7953_PHCAL_DEFAULT_CT : ADE7953_PHCAL_DEFAULT ;
} else {
Ade7953 . calib_data [ channel ] [ i ] = ADE7953_GAIN_DEFAULT ;
}
2022-09-13 16:58:22 +01:00
}
}
2023-01-04 14:00:43 +00:00
String calib = " " ;
# ifdef USE_UFILESYS
calib = TfsLoadString ( " /calib.dat " ) ;
# endif // USE_UFILESYS
2022-09-13 14:35:09 +01:00
# ifdef USE_RULES
// rule3 on file#calib.dat do {"angles":{"angle0":180,"angle1":176}} endon
2023-01-04 14:00:43 +00:00
if ( ! calib . length ( ) ) {
calib = RuleLoadFile ( " CALIB.DAT " ) ;
}
# endif // USE_RULES
2022-09-13 14:35:09 +01:00
if ( calib . length ( ) ) {
// AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: File '%s'"), calib.c_str());
Ade7953SetDefaults ( calib . c_str ( ) ) ;
}
}
void Ade7953DrvInit ( void ) {
2022-10-26 16:16:36 +01:00
if ( PinUsed ( GPIO_ADE7953_IRQ , GPIO_ANY ) ) { // Irq is not supported...
2021-08-23 15:18:21 +01:00
uint32_t pin_irq = Pin ( GPIO_ADE7953_IRQ , GPIO_ANY ) ;
2022-10-26 16:16:36 +01:00
pinMode ( pin_irq , INPUT ) ; // Related to resetPins() - Must be set to input
2023-01-29 15:09:13 +00:00
// 0 (1 = Shelly 2.5), 1 (2 = Shelly EM), 2 (3 = Shelly Plus 2PM), 3 (4 = Shelly Pro 1PM), 4 (5 = Shelly Pro 2PM), 5 (6 = Shelly Pro 4PM)
2022-10-26 16:16:36 +01:00
Ade7953 . model = GetPin ( pin_irq ) - AGPIO ( GPIO_ADE7953_IRQ ) ;
2022-01-04 16:41:47 +00:00
2022-10-26 16:16:36 +01:00
int pin_reset = Pin ( GPIO_ADE7953_RST ) ; // -1 if not defined
2022-10-03 16:13:01 +01:00
# ifdef ESP8266
2022-09-13 14:35:09 +01:00
if ( ADE7953_SHELLY_EM = = Ade7953 . model ) {
2022-10-03 16:13:01 +01:00
if ( - 1 = = pin_reset ) {
pin_reset = 16 ;
}
}
# endif
2022-10-26 16:16:36 +01:00
if ( pin_reset > = 0 ) {
2022-10-03 16:13:01 +01:00
digitalWrite ( pin_reset , 0 ) ;
2022-10-26 16:16:36 +01:00
pinMode ( pin_reset , OUTPUT ) ; // Reset pin ADE7953
delay ( 1 ) ; // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs.
2022-10-03 16:13:01 +01:00
digitalWrite ( pin_reset , 1 ) ;
2022-10-26 16:16:36 +01:00
if ( Ade7953 . model < ADE7953_SHELLY_PRO_1PM ) {
pinMode ( pin_reset , INPUT ) ;
}
2022-01-04 16:41:47 +00:00
}
2023-01-21 14:42:31 +00:00
# ifdef USE_ESP32_SPI
2023-01-21 13:30:35 +00:00
# ifdef USE_SHELLY_PRO
if ( Ade7953 . model = = ADE7953_SHELLY_PRO_4PM ) {
ShellyPro4Reset ( ) ;
}
# endif // USE_SHELLY_PRO
2023-01-21 14:42:31 +00:00
# endif // USE_ESP32_SPI
2022-10-26 16:16:36 +01:00
delay ( 100 ) ; // Need 100mS to init ADE7953
# ifdef USE_ESP32_SPI
Ade7953 . pin_cs [ 0 ] = - 1 ;
Ade7953 . pin_cs [ 1 ] = - 1 ;
if ( Ade7953 . model > = ADE7953_SHELLY_PRO_1PM ) { // SPI
if ( PinUsed ( GPIO_ADE7953_CS ) ) { // ADE7953 CS1 enabled (Pro 1PM/2PM)
Ade7953 . pin_cs [ 0 ] = Pin ( GPIO_ADE7953_CS ) ;
digitalWrite ( Ade7953 . pin_cs [ 0 ] , 1 ) ; // ADE7953 CS1 enabled (Pro 2PM)
pinMode ( Ade7953 . pin_cs [ 0 ] , OUTPUT ) ;
Ade7953 . pin_cs [ 1 ] = Pin ( GPIO_ADE7953_CS , 1 ) ;
if ( Ade7953 . pin_cs [ 1 ] > - 1 ) { // ADE7953 CS2 enabled (Pro 2PM)
digitalWrite ( Ade7953 . pin_cs [ 1 ] , 1 ) ;
pinMode ( Ade7953 . pin_cs [ 1 ] , OUTPUT ) ;
} else {
Ade7953 . model = ADE7953_SHELLY_PRO_1PM ;
}
Ade7953 . cs_index = 0 ;
2023-02-04 16:48:53 +00:00
Ade7953 . use_spi = true ;
2022-10-26 16:16:36 +01:00
SPI . begin ( Pin ( GPIO_SPI_CLK ) , Pin ( GPIO_SPI_MISO ) , Pin ( GPIO_SPI_MOSI ) , - 1 ) ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " SPI: ADE7953 found " ) ) ;
} else {
return ; // No CS pin defined
}
} else {
# endif // USE_ESP32_SPI
2022-10-27 16:52:44 +01:00
if ( ! I2cSetDevice ( ADE7953_ADDR ) ) {
return ;
2019-09-08 15:57:56 +01:00
}
2019-11-09 17:34:22 +00:00
I2cSetActiveFound ( ADE7953_ADDR , " ADE7953 " ) ;
2022-10-26 16:16:36 +01:00
# ifdef USE_ESP32_SPI
}
# endif // USE_ESP32_SPI
2023-01-25 16:05:48 +00:00
if ( EnergyGetCalibration ( ENERGY_POWER_CALIBRATION ) = = HLW_PREF_PULSE ) {
2023-01-27 14:53:40 +00:00
for ( uint32_t i = 0 ; i < ADE7953_MAX_CHANNEL ; i + + ) {
2023-01-25 16:05:48 +00:00
EnergySetCalibration ( ENERGY_POWER_CALIBRATION , ADE7953_PREF , i ) ;
EnergySetCalibration ( ENERGY_VOLTAGE_CALIBRATION , ADE7953_UREF , i ) ;
EnergySetCalibration ( ENERGY_CURRENT_CALIBRATION , ADE7953_IREF , i ) ;
}
2022-10-26 16:16:36 +01:00
}
2022-09-13 14:35:09 +01:00
2022-10-26 16:16:36 +01:00
Ade7953Defaults ( ) ;
2022-10-30 11:20:56 +00:00
Ade7953 . init_step = 3 ;
2022-10-26 16:16:36 +01:00
2023-01-24 15:54:03 +00:00
// Energy->phase_count = 1;
// Energy->voltage_common = false;
// Energy->frequency_common = false;
// Energy->use_overtemp = false;
2022-10-26 16:16:36 +01:00
if ( ADE7953_SHELLY_PRO_1PM = = Ade7953 . model ) {
} else {
2023-01-24 15:54:03 +00:00
Energy - > phase_count = 2 ; // Handle two channels as two phases
2022-10-26 16:16:36 +01:00
if ( ADE7953_SHELLY_PRO_2PM = = Ade7953 . model ) {
} else {
2023-01-24 15:54:03 +00:00
Energy - > voltage_common = true ; // Use common voltage
Energy - > frequency_common = true ; // Use common frequency
2023-01-26 16:27:49 +00:00
if ( ADE7953_SHELLY_PRO_4PM = = Ade7953 . model ) {
Energy - > phase_count = 4 ;
}
2022-10-13 13:32:35 +01:00
}
2019-04-14 17:20:24 +01:00
}
2023-01-24 15:54:03 +00:00
Energy - > use_overtemp = true ; // Use global temperature for overtemp detection
2022-10-26 16:16:36 +01:00
if ( ADE7953_SHELLY_EM = = Ade7953 . model ) {
2023-01-24 15:54:03 +00:00
Energy - > local_energy_active_export = true ;
2022-10-26 16:16:36 +01:00
}
TasmotaGlobal . energy_driver = XNRG_07 ;
2019-04-14 17:20:24 +01:00
}
}
2022-09-13 14:35:09 +01:00
bool Ade7953Command ( void ) {
2019-04-14 17:20:24 +01:00
bool serviced = true ;
2023-01-27 14:53:40 +00:00
if ( XdrvMailbox . index > ADE7953_MAX_CHANNEL ) { return false ; } ;
uint32_t channel = XdrvMailbox . index - 1 ;
2023-01-26 16:27:49 +00:00
if ( ADE7953_SHELLY_PRO_4PM ! = Ade7953 . model ) {
channel = ( 2 = = XdrvMailbox . index ) ? 1 : 0 ;
}
2019-07-01 17:20:43 +01:00
uint32_t value = ( uint32_t ) ( CharToFloat ( XdrvMailbox . data ) * 100 ) ; // 1.23 = 123
2019-04-14 17:20:24 +01:00
2023-01-24 15:54:03 +00:00
if ( CMND_POWERCAL = = Energy - > command_code ) {
2019-04-14 17:20:24 +01:00
if ( 1 = = XdrvMailbox . payload ) { XdrvMailbox . payload = ADE7953_PREF ; }
// Service in xdrv_03_energy.ino
}
2023-01-24 15:54:03 +00:00
else if ( CMND_VOLTAGECAL = = Energy - > command_code ) {
2019-04-14 17:20:24 +01:00
if ( 1 = = XdrvMailbox . payload ) { XdrvMailbox . payload = ADE7953_UREF ; }
// Service in xdrv_03_energy.ino
}
2023-01-24 15:54:03 +00:00
else if ( CMND_CURRENTCAL = = Energy - > command_code ) {
2019-04-14 17:20:24 +01:00
if ( 1 = = XdrvMailbox . payload ) { XdrvMailbox . payload = ADE7953_IREF ; }
// Service in xdrv_03_energy.ino
}
2023-01-24 15:54:03 +00:00
else if ( CMND_POWERSET = = Energy - > command_code ) {
2019-09-15 12:10:32 +01:00
if ( XdrvMailbox . data_len & & Ade7953 . active_power [ channel ] ) {
2022-10-26 16:16:36 +01:00
if ( ( value > 100 ) & & ( value < 200000 ) ) { // Between 1W and 2000W
2022-10-30 11:20:56 +00:00
# ifdef ADE7953_ACCU_ENERGY
float power_calibration = ( float ) ( Ade7953 . active_power [ channel ] * 1000 ) / value ; // 0.00 W
power_calibration * = ADE7953_POWER_CORRECTION ;
XdrvMailbox . payload = ( uint32_t ) power_calibration ; // 0.00 W
# else // No ADE7953_ACCU_ENERGY
2022-10-29 18:08:06 +01:00
XdrvMailbox . payload = ( Ade7953 . active_power [ channel ] * 1000 ) / value ; // 0.00 W
2022-10-30 11:20:56 +00:00
# endif // ADE7953_ACCU_ENERGY
2019-04-18 13:13:14 +01:00
}
2019-04-14 17:20:24 +01:00
}
}
2023-01-24 15:54:03 +00:00
else if ( CMND_VOLTAGESET = = Energy - > command_code ) {
2022-10-26 16:16:36 +01:00
if ( XdrvMailbox . data_len & & Ade7953 . voltage_rms [ channel ] ) {
if ( ( value > 10000 ) & & ( value < 26000 ) ) { // Between 100V and 260V
2022-10-29 18:08:06 +01:00
XdrvMailbox . payload = ( Ade7953 . voltage_rms [ channel ] * 100 ) / value ; // 0.00 V
2019-04-18 13:13:14 +01:00
}
2019-04-14 17:20:24 +01:00
}
}
2023-01-24 15:54:03 +00:00
else if ( CMND_CURRENTSET = = Energy - > command_code ) {
2019-09-15 12:10:32 +01:00
if ( XdrvMailbox . data_len & & Ade7953 . current_rms [ channel ] ) {
2022-10-26 16:16:36 +01:00
if ( ( value > 2000 ) & & ( value < 1000000 ) ) { // Between 20mA and 10A
2022-10-29 18:08:06 +01:00
XdrvMailbox . payload = ( ( Ade7953 . current_rms [ channel ] * 100 ) / value ) * 100 ; // 0.00 mA
2019-04-18 13:13:14 +01:00
}
2019-04-14 17:20:24 +01:00
}
}
2022-10-26 16:16:36 +01:00
else serviced = false ; // Unknown command
2019-04-14 17:20:24 +01:00
return serviced ;
}
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-11-11 09:44:56 +00:00
bool Xnrg07 ( uint32_t function ) {
2022-10-26 16:16:36 +01:00
if ( ! I2cEnabled ( XI2C_07 ) & & ( SPI_MOSI_MISO ! = TasmotaGlobal . spi_enabled ) ) { return false ; }
2019-11-03 16:54:39 +00:00
2019-09-08 15:57:56 +01:00
bool result = false ;
switch ( function ) {
2023-02-22 09:30:47 +00:00
# ifdef USE_ESP32_SPI
2023-02-04 16:48:53 +00:00
case FUNC_ENERGY_EVERY_SECOND : // Use energy interrupt timer (fails on SPI)
if ( ! Ade7953 . use_spi ) { // No SPI
Ade7953EnergyEverySecond ( ) ;
}
break ;
case FUNC_EVERY_SECOND : // Use loop timer (without interrupt)
if ( Ade7953 . use_spi ) { // SPI
Ade7953EnergyEverySecond ( ) ;
}
2019-09-08 15:57:56 +01:00
break ;
2023-02-22 09:30:47 +00:00
# else // ESP8266
case FUNC_ENERGY_EVERY_SECOND : // Use energy interrupt timer
Ade7953EnergyEverySecond ( ) ;
break ;
# endif // USE_ESP32_SPI
2019-09-08 15:57:56 +01:00
case FUNC_COMMAND :
result = Ade7953Command ( ) ;
break ;
case FUNC_PRE_INIT :
Ade7953DrvInit ( ) ;
break ;
2019-04-14 17:20:24 +01:00
}
return result ;
}
# endif // USE_ADE7953
# endif // USE_ENERGY_SENSOR
2022-10-26 16:16:36 +01:00
# endif // USE_I2C or USE_ESP_SPI