mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-28 13:16:32 +00:00
Add Shelly 2.5 Energy Monitoring (#5592)
Add Shelly 2.5 Energy Monitoring (#5592)
This commit is contained in:
parent
d176285a25
commit
6adb513cd6
@ -1,6 +1,7 @@
|
||||
/* 6.5.0.8 20190413
|
||||
* Fix use of SerialDelimiter value 128 (#5634)
|
||||
* Fix lost syslog connection regression from 6.5.0.4
|
||||
* Add Shelly 2.5 Energy Monitoring (#5592)
|
||||
*
|
||||
* 6.5.0.7 20190410
|
||||
* Add command LedMask to assign which relay has access to power LED (#5602, #5612)
|
||||
|
@ -342,6 +342,7 @@
|
||||
// #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem)
|
||||
// #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code)
|
||||
// #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code)
|
||||
#define USE_ADE7953 // Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5)
|
||||
|
||||
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
|
||||
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
||||
|
244
sonoff/xnrg_07_ade7953.ino
Normal file
244
sonoff/xnrg_07_ade7953.ino
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
xnrg_07_ade7953.ino - ADE7953 energy sensor support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_I2C
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
#ifdef USE_ADE7953
|
||||
/*********************************************************************************************\
|
||||
* ADE7953 - Energy (Shelly 2.5)
|
||||
*
|
||||
* Based on datasheet from https://www.analog.com/en/products/ade7953.html
|
||||
*
|
||||
* I2C Address: 0x38
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XNRG_07 7
|
||||
|
||||
#define ADE7953_PREF 1540
|
||||
#define ADE7953_UREF 26000
|
||||
#define ADE7953_IREF 10000
|
||||
|
||||
#define ADE7953_ADDR 0x38
|
||||
|
||||
uint32_t ade7953_active_power = 0;
|
||||
uint32_t ade7953_active_power1 = 0;
|
||||
uint32_t ade7953_active_power2 = 0;
|
||||
uint32_t ade7953_current_rms = 0;
|
||||
uint32_t ade7953_current_rms1 = 0;
|
||||
uint32_t ade7953_current_rms2 = 0;
|
||||
uint32_t ade7953_voltage_rms = 0;
|
||||
uint8_t ade7953_init = 0;
|
||||
|
||||
int Ade7953RegSize(uint16_t reg)
|
||||
{
|
||||
int size = 0;
|
||||
switch ((reg >> 8) & 0x0F) {
|
||||
case 0x03:
|
||||
size++;
|
||||
case 0x02:
|
||||
size++;
|
||||
case 0x01:
|
||||
size++;
|
||||
case 0x00:
|
||||
case 0x07:
|
||||
case 0x08:
|
||||
size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void Ade7953Write(uint16_t reg, uint32_t val)
|
||||
{
|
||||
int size = Ade7953RegSize(reg);
|
||||
if (size) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Ade7953Read(uint16_t reg)
|
||||
{
|
||||
uint32_t response = 0;
|
||||
|
||||
int size = Ade7953RegSize(reg);
|
||||
if (size) {
|
||||
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 (int i = 0; i < size; i++) {
|
||||
response = response << 8 | Wire.read(); // receive DATA (MSB first)
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
void Ade7953Init(void)
|
||||
{
|
||||
Ade7953Write(0x102, 0x0004); // Locking the communication interface (Clear bit COMM_LOCK), Enable HPF
|
||||
Ade7953Write(0x0FE, 0x00AD); // Unlock register 0x120
|
||||
Ade7953Write(0x120, 0x0030); // Configure optimum setting
|
||||
}
|
||||
|
||||
void Ade7953GetData(void)
|
||||
{
|
||||
ade7953_voltage_rms = Ade7953Read(0x31C); // Both relays
|
||||
ade7953_current_rms1 = Ade7953Read(0x31B); // Relay 1
|
||||
if (ade7953_current_rms1 < 2000) { // No load threshold (20mA)
|
||||
ade7953_current_rms1 = 0;
|
||||
ade7953_active_power1 = 0;
|
||||
} else {
|
||||
ade7953_active_power1 = (int32_t)Ade7953Read(0x313) * -1; // Relay 1
|
||||
}
|
||||
ade7953_current_rms2 = Ade7953Read(0x31A); // Relay 2
|
||||
if (ade7953_current_rms2 < 2000) { // No load threshold (20mA)
|
||||
ade7953_current_rms2 = 0;
|
||||
ade7953_active_power2 = 0;
|
||||
} else {
|
||||
ade7953_active_power2 = (int32_t)Ade7953Read(0x312); // Relay 2
|
||||
}
|
||||
// First phase only supports accumulated Current and Power
|
||||
ade7953_current_rms = ade7953_current_rms1 + ade7953_current_rms2;
|
||||
ade7953_active_power = ade7953_active_power1 + ade7953_active_power2;
|
||||
|
||||
if (energy_power_on) { // Powered on
|
||||
energy_voltage = (float)ade7953_voltage_rms / Settings.energy_voltage_calibration;
|
||||
energy_active_power = (float)ade7953_active_power / (Settings.energy_power_calibration / 10);
|
||||
if (0 == energy_active_power) {
|
||||
energy_current = 0;
|
||||
} else {
|
||||
energy_current = (float)ade7953_current_rms / (Settings.energy_current_calibration * 10);
|
||||
}
|
||||
} else { // Powered off
|
||||
energy_voltage = 0;
|
||||
energy_active_power = 0;
|
||||
energy_current = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Ade7953EverySecond()
|
||||
{
|
||||
if (ade7953_active_power) {
|
||||
energy_kWhtoday_delta += ((ade7953_active_power * (100000 / (Settings.energy_power_calibration / 10))) / 3600);
|
||||
EnergyUpdateToday();
|
||||
}
|
||||
if (ade7953_init) {
|
||||
if (1 == ade7953_init) {
|
||||
Ade7953Init();
|
||||
}
|
||||
ade7953_init--;
|
||||
}
|
||||
else {
|
||||
Ade7953GetData();
|
||||
}
|
||||
}
|
||||
|
||||
void Ade7953DrvInit(void)
|
||||
{
|
||||
if (!energy_flg) {
|
||||
if (i2c_flg && (pin[GPIO_ADE7953_IRQ] < 99)) { // Irq on GPIO16 is not supported...
|
||||
delay(100); // Need 100mS to init ADE7953
|
||||
if (I2cDevice(ADE7953_ADDR)) {
|
||||
if (HLW_PREF_PULSE == Settings.energy_power_calibration) {
|
||||
Settings.energy_power_calibration = ADE7953_PREF;
|
||||
Settings.energy_voltage_calibration = ADE7953_UREF;
|
||||
Settings.energy_current_calibration = ADE7953_IREF;
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "ADE7953", ADE7953_ADDR);
|
||||
ade7953_init = 2;
|
||||
energy_flg = XNRG_07;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Ade7953Command(void)
|
||||
{
|
||||
bool serviced = true;
|
||||
|
||||
double value = CharToDouble(XdrvMailbox.data);
|
||||
|
||||
if (CMND_POWERCAL == energy_command_code) {
|
||||
if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_PREF; }
|
||||
// Service in xdrv_03_energy.ino
|
||||
}
|
||||
else if (CMND_VOLTAGECAL == energy_command_code) {
|
||||
if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_UREF; }
|
||||
// Service in xdrv_03_energy.ino
|
||||
}
|
||||
else if (CMND_CURRENTCAL == energy_command_code) {
|
||||
if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_IREF; }
|
||||
// Service in xdrv_03_energy.ino
|
||||
}
|
||||
else if (CMND_POWERSET == energy_command_code) {
|
||||
if (XdrvMailbox.data_len && ade7953_active_power) {
|
||||
Settings.energy_power_calibration = (uint32_t)((double)ade7953_active_power / (value / 10)); // W
|
||||
}
|
||||
}
|
||||
else if (CMND_VOLTAGESET == energy_command_code) {
|
||||
if (XdrvMailbox.data_len && ade7953_voltage_rms) {
|
||||
Settings.energy_voltage_calibration = (uint32_t)((double)ade7953_voltage_rms / value); // V
|
||||
}
|
||||
}
|
||||
else if (CMND_CURRENTSET == energy_command_code) {
|
||||
if (XdrvMailbox.data_len && ade7953_current_rms) {
|
||||
Settings.energy_current_calibration = (uint32_t)((double)ade7953_current_rms / (value * 10)); // A
|
||||
}
|
||||
}
|
||||
else serviced = false; // Unknown command
|
||||
|
||||
return serviced;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
int Xnrg07(uint8_t function)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (FUNC_PRE_INIT == function) {
|
||||
Ade7953DrvInit();
|
||||
}
|
||||
else if (XNRG_07 == energy_flg) {
|
||||
switch (function) {
|
||||
case FUNC_EVERY_SECOND:
|
||||
Ade7953EverySecond();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = Ade7953Command();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_ADE7953
|
||||
#endif // USE_ENERGY_SENSOR
|
||||
#endif // USE_I2C
|
Loading…
x
Reference in New Issue
Block a user