mirror of https://github.com/arendst/Tasmota.git
Merge pull request #6046 from burundiocibu/multi-219
Added support for multiple INA219 devices on single I2C bus
This commit is contained in:
commit
fa0315f1f4
|
@ -84,20 +84,19 @@
|
||||||
#define INA219_REG_CURRENT (0x04)
|
#define INA219_REG_CURRENT (0x04)
|
||||||
#define INA219_REG_CALIBRATION (0x05)
|
#define INA219_REG_CALIBRATION (0x05)
|
||||||
|
|
||||||
uint8_t ina219_type = 0;
|
uint8_t ina219_type[4] = {0,0,0,0};
|
||||||
uint8_t ina219_address;
|
|
||||||
uint8_t ina219_addresses[] = { INA219_ADDRESS1, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 };
|
uint8_t ina219_addresses[] = { INA219_ADDRESS1, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 };
|
||||||
|
|
||||||
uint32_t ina219_cal_value = 0;
|
uint32_t ina219_cal_value = 0;
|
||||||
// The following multiplier is used to convert raw current values to mA, taking into account the current config settings
|
// The following multiplier is used to convert raw current values to mA, taking into account the current config settings
|
||||||
uint32_t ina219_current_divider_ma = 0;
|
uint32_t ina219_current_divider_ma = 0;
|
||||||
|
|
||||||
uint8_t ina219_valid = 0;
|
uint8_t ina219_valid[4] = {0,0,0,0};
|
||||||
float ina219_voltage = 0;
|
float ina219_voltage[4] = {0,0,0,0};
|
||||||
float ina219_current = 0;
|
float ina219_current[4] = {0,0,0,0};
|
||||||
char ina219_types[] = "INA219";
|
char ina219_types[] = "INA219";
|
||||||
|
|
||||||
bool Ina219SetCalibration(uint8_t mode)
|
bool Ina219SetCalibration(uint8_t mode, uint16_t addr)
|
||||||
{
|
{
|
||||||
uint16_t config = 0;
|
uint16_t config = 0;
|
||||||
|
|
||||||
|
@ -120,40 +119,40 @@ bool Ina219SetCalibration(uint8_t mode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Set Calibration register to 'Cal' calculated above
|
// Set Calibration register to 'Cal' calculated above
|
||||||
bool success = I2cWrite16(ina219_address, INA219_REG_CALIBRATION, ina219_cal_value);
|
bool success = I2cWrite16(addr, INA219_REG_CALIBRATION, ina219_cal_value);
|
||||||
if (success) {
|
if (success) {
|
||||||
// Set Config register to take into account the settings above
|
// Set Config register to take into account the settings above
|
||||||
I2cWrite16(ina219_address, INA219_REG_CONFIG, config);
|
I2cWrite16(addr, INA219_REG_CONFIG, config);
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Ina219GetShuntVoltage_mV(void)
|
float Ina219GetShuntVoltage_mV(uint16_t addr)
|
||||||
{
|
{
|
||||||
// raw shunt voltage (16-bit signed integer, so +-32767)
|
// raw shunt voltage (16-bit signed integer, so +-32767)
|
||||||
int16_t value = I2cReadS16(ina219_address, INA219_REG_SHUNTVOLTAGE);
|
int16_t value = I2cReadS16(addr, INA219_REG_SHUNTVOLTAGE);
|
||||||
// shunt voltage in mV (so +-327mV)
|
// shunt voltage in mV (so +-327mV)
|
||||||
return value * 0.01;
|
return value * 0.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Ina219GetBusVoltage_V(void)
|
float Ina219GetBusVoltage_V(uint16_t addr)
|
||||||
{
|
{
|
||||||
// Shift to the right 3 to drop CNVR and OVF and multiply by LSB
|
// Shift to the right 3 to drop CNVR and OVF and multiply by LSB
|
||||||
// raw bus voltage (16-bit signed integer, so +-32767)
|
// raw bus voltage (16-bit signed integer, so +-32767)
|
||||||
int16_t value = (int16_t)(((uint16_t)I2cReadS16(ina219_address, INA219_REG_BUSVOLTAGE) >> 3) * 4);
|
int16_t value = (int16_t)(((uint16_t)I2cReadS16(addr, INA219_REG_BUSVOLTAGE) >> 3) * 4);
|
||||||
// bus voltage in volts
|
// bus voltage in volts
|
||||||
return value * 0.001;
|
return value * 0.001;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Ina219GetCurrent_mA(void)
|
float Ina219GetCurrent_mA(uint16_t addr)
|
||||||
{
|
{
|
||||||
// Sometimes a sharp load will reset the INA219, which will reset the cal register,
|
// Sometimes a sharp load will reset the INA219, which will reset the cal register,
|
||||||
// meaning CURRENT and POWER will not be available ... avoid this by always setting
|
// meaning CURRENT and POWER will not be available ... avoid this by always setting
|
||||||
// a cal value even if it's an unfortunate extra step
|
// a cal value even if it's an unfortunate extra step
|
||||||
I2cWrite16(ina219_address, INA219_REG_CALIBRATION, ina219_cal_value);
|
I2cWrite16(addr, INA219_REG_CALIBRATION, ina219_cal_value);
|
||||||
// Now we can safely read the CURRENT register!
|
// Now we can safely read the CURRENT register!
|
||||||
// raw current value (16-bit signed integer, so +-32767)
|
// raw current value (16-bit signed integer, so +-32767)
|
||||||
float value = I2cReadS16(ina219_address, INA219_REG_CURRENT);
|
float value = I2cReadS16(addr, INA219_REG_CURRENT);
|
||||||
value /= ina219_current_divider_ma;
|
value /= ina219_current_divider_ma;
|
||||||
// current value in mA, taking into account the config settings and current LSB
|
// current value in mA, taking into account the config settings and current LSB
|
||||||
return value;
|
return value;
|
||||||
|
@ -161,9 +160,15 @@ float Ina219GetCurrent_mA(void)
|
||||||
|
|
||||||
bool Ina219Read(void)
|
bool Ina219Read(void)
|
||||||
{
|
{
|
||||||
ina219_voltage = Ina219GetBusVoltage_V() + (Ina219GetShuntVoltage_mV() / 1000);
|
for (int i=0; i<sizeof(ina219_type); i++) {
|
||||||
ina219_current = Ina219GetCurrent_mA() / 1000;
|
if (!ina219_type[i])
|
||||||
ina219_valid = SENSOR_MAX_MISS;
|
continue;
|
||||||
|
uint16_t addr = ina219_addresses[i];
|
||||||
|
ina219_voltage[i] = Ina219GetBusVoltage_V(addr) + (Ina219GetShuntVoltage_mV(addr) / 1000);
|
||||||
|
ina219_current[i] = Ina219GetCurrent_mA(addr) / 1000;
|
||||||
|
ina219_valid[i] = SENSOR_MAX_MISS;
|
||||||
|
// AddLogMissed(ina219_types, ina219_valid);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,14 +197,13 @@ bool Ina219CommandSensor(void)
|
||||||
|
|
||||||
void Ina219Detect(void)
|
void Ina219Detect(void)
|
||||||
{
|
{
|
||||||
if (ina219_type) { return; }
|
for (int i=0; i<sizeof(ina219_type); i++) {
|
||||||
|
if (ina219_type[i])
|
||||||
for (uint32_t i = 0; i < sizeof(ina219_addresses); i++) {
|
continue;
|
||||||
ina219_address = ina219_addresses[i];
|
uint16_t addr = ina219_addresses[i];
|
||||||
if (Ina219SetCalibration(Settings.ina219_mode)) {
|
if (Ina219SetCalibration(Settings.ina219_mode, addr)) {
|
||||||
ina219_type = 1;
|
ina219_type[i] = 1;
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, ina219_types, ina219_address);
|
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, ina219_types, addr);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,41 +211,50 @@ void Ina219Detect(void)
|
||||||
void Ina219EverySecond(void)
|
void Ina219EverySecond(void)
|
||||||
{
|
{
|
||||||
if (87 == (uptime %100)) {
|
if (87 == (uptime %100)) {
|
||||||
// 2mS
|
// 4 x 2mS
|
||||||
Ina219Detect();
|
Ina219Detect();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 3mS
|
// 4 x 3mS
|
||||||
if (ina219_type) {
|
Ina219Read();
|
||||||
if (!Ina219Read()) {
|
|
||||||
AddLogMissed(ina219_types, ina219_valid);
|
|
||||||
// if (!ina219_valid) { ina219_type = 0; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
const char HTTP_SNS_INA219_DATA[] PROGMEM =
|
const char HTTP_SNS_INA219_DATA[] PROGMEM =
|
||||||
"{s}INA219 " D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"
|
"{s}%s " D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"
|
||||||
"{s}INA219 " D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"
|
"{s}%s " D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"
|
||||||
"{s}INA219 " D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}";
|
"{s}%s " D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}";
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
|
|
||||||
void Ina219Show(bool json)
|
void Ina219Show(bool json)
|
||||||
{
|
{
|
||||||
if (ina219_valid) {
|
int num_found=0;
|
||||||
float fpower = ina219_voltage * ina219_current;
|
for (int i=0; i<sizeof(ina219_type); i++)
|
||||||
char voltage[33];
|
if (ina219_type[i] && ina219_valid[i])
|
||||||
dtostrfd(ina219_voltage, Settings.flag2.voltage_resolution, voltage);
|
num_found++;
|
||||||
char power[33];
|
|
||||||
dtostrfd(fpower, Settings.flag2.wattage_resolution, power);
|
int sensor_num = 0;
|
||||||
char current[33];
|
for (int i=0; i<sizeof(ina219_type); i++) {
|
||||||
dtostrfd(ina219_current, Settings.flag2.current_resolution, current);
|
if (!ina219_type[i] || !ina219_valid[i])
|
||||||
|
continue;
|
||||||
|
sensor_num++;
|
||||||
|
|
||||||
|
char voltage[16];
|
||||||
|
dtostrfd(ina219_voltage[i], Settings.flag2.voltage_resolution, voltage);
|
||||||
|
char current[16];
|
||||||
|
dtostrfd(ina219_current[i], Settings.flag2.current_resolution, current);
|
||||||
|
char power[16];
|
||||||
|
dtostrfd(ina219_voltage[i] * ina219_current[i], Settings.flag2.wattage_resolution, power);
|
||||||
|
char name[16];
|
||||||
|
if (num_found>1)
|
||||||
|
snprintf_P(name, sizeof(name), PSTR("%s%c%d"), ina219_types, IndexSeparator(), sensor_num);
|
||||||
|
else
|
||||||
|
snprintf_P(name, sizeof(name), PSTR("%s"), ina219_types);
|
||||||
|
|
||||||
if (json) {
|
if (json) {
|
||||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"),
|
ResponseAppend_P(PSTR(",\"%s\":{\"Id\":%02x,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"),
|
||||||
ina219_types, voltage, current, power);
|
name, ina219_addresses[i], voltage, current, power);
|
||||||
#ifdef USE_DOMOTICZ
|
#ifdef USE_DOMOTICZ
|
||||||
if (0 == tele_period) {
|
if (0 == tele_period) {
|
||||||
DomoticzSensor(DZ_VOLTAGE, voltage);
|
DomoticzSensor(DZ_VOLTAGE, voltage);
|
||||||
|
@ -250,7 +263,7 @@ void Ina219Show(bool json)
|
||||||
#endif // USE_DOMOTICZ
|
#endif // USE_DOMOTICZ
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
} else {
|
} else {
|
||||||
WSContentSend_PD(HTTP_SNS_INA219_DATA, voltage, current, power);
|
WSContentSend_PD(HTTP_SNS_INA219_DATA, name, voltage, name, current, name, power);
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue