diff --git a/tasmota/xsns_13_ina219.ino b/tasmota/xsns_13_ina219.ino index 738c9aabe..392437d8d 100644 --- a/tasmota/xsns_13_ina219.ino +++ b/tasmota/xsns_13_ina219.ino @@ -30,6 +30,8 @@ #define XSNS_13 13 #define XI2C_14 14 // See I2CDEVICES.md +#define INA219_MAX_COUNT 4 + #define INA219_ADDRESS1 (0x40) // 1000000 (A0+A1=GND) #define INA219_ADDRESS2 (0x41) // 1000000 (A0=Vcc, A1=GND) #define INA219_ADDRESS3 (0x44) // 1000000 (A0=GND, A1=Vcc) @@ -94,25 +96,43 @@ #define INA219_DEFAULT_SHUNT_RESISTOR_MILLIOHMS (100.0) // 0.1 Ohm -uint8_t ina219_type[4] = {0,0,0,0}; -uint8_t ina219_addresses[] = { INA219_ADDRESS1, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 }; - #ifdef DEBUG_TASMOTA_SENSOR // temporary strings for floating point in debug messages char __ina219_dbg1[10]; char __ina219_dbg2[10]; #endif +struct INA219_Channel_Data { + float voltage; + float current; + uint8_t active; + uint8_t valid; +}; + +struct INA219_Data { + struct INA219_Channel_Data chan[INA219_MAX_COUNT]; + float current_multiplier; + uint8_t count; +}; + +struct INA219_Data *Ina219Data = nullptr; + +const char INA219_TYPE[] = "INA219"; +const uint8_t INA219_ADDRESSES[] = { INA219_ADDRESS1, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 }; + +//uint8_t ina219_type[4] = {0,0,0,0}; +//uint8_t ina219_addresses[] = { INA219_ADDRESS1, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 }; + + // The following multiplier is used to convert shunt voltage (in mV) to current (in A) // Current_A = ShuntVoltage_mV / ShuntResistor_milliOhms = ShuntVoltage_mV * ina219_current_multiplier // ina219_current_multiplier = 1 / ShuntResistor_milliOhms -float ina219_current_multiplier; +//float Ina219Data->current_multiplier -uint8_t ina219_valid[4] = {0,0,0,0}; -float ina219_voltage[4] = {0,0,0,0}; -float ina219_current[4] = {0,0,0,0}; -char ina219_types[] = "INA219"; -uint8_t ina219_count = 0; +//uint8_t ina219_valid[4] = {0,0,0,0}; +//float ina219_voltage[4] = {0,0,0,0}; +//float ina219_current[4] = {0,0,0,0}; +//uint8_t ina219_count = 0; /*********************************************************************************************\ * Calculate current multiplier depending on the selected mode @@ -137,9 +157,9 @@ bool Ina219SetCalibration(uint8_t mode, uint16_t addr) if (mode < 5) { // All legacy modes 0..2 are handled the same and consider default 0.1 shunt resistor - ina219_current_multiplier = 1.0 / INA219_DEFAULT_SHUNT_RESISTOR_MILLIOHMS; + Ina219Data->current_multiplier = 1.0 / INA219_DEFAULT_SHUNT_RESISTOR_MILLIOHMS; #ifdef DEBUG_TASMOTA_SENSOR - dtostrfd(ina219_current_multiplier,5,__ina219_dbg1); + dtostrfd(Ina219Data->current_multiplier,5,__ina219_dbg1); DEBUG_SENSOR_LOG("Ina219SetCalibration: cur_mul=%s",__ina219_dbg1); #endif } @@ -149,9 +169,9 @@ bool Ina219SetCalibration(uint8_t mode, uint16_t addr) int shunt_milliOhms = mode / 10; for ( ; mult > 0 ; mult-- ) shunt_milliOhms *= 10; - ina219_current_multiplier = 1.0 / shunt_milliOhms; + Ina219Data->current_multiplier = 1.0 / shunt_milliOhms; #ifdef DEBUG_TASMOTA_SENSOR - dtostrfd(ina219_current_multiplier,5,__ina219_dbg1); + dtostrfd(Ina219Data->current_multiplier,5,__ina219_dbg1); DEBUG_SENSOR_LOG("Ina219SetCalibration: shunt=%dmO => cur_mul=%s",shunt_milliOhms,__ina219_dbg1); #endif } @@ -168,41 +188,25 @@ float Ina219GetShuntVoltage_mV(uint16_t addr) { // raw shunt voltage (16-bit signed integer, so +-32767) int16_t value = I2cReadS16(addr, INA219_REG_SHUNTVOLTAGE); - DEBUG_SENSOR_LOG("Ina219GetShuntVoltage_mV: ShReg = 0x%04X",value); + DEBUG_SENSOR_LOG("Ina219GetShuntVoltage_mV: ShReg = 0x%04X (%d)",value, value); // convert to shunt voltage in mV (so +-327mV) (LSB=10µV=0.01mV) - return value * 0.01; + return (float)value * 0.01; } float Ina219GetBusVoltage_V(uint16_t addr) { // Shift 3 to the right to drop CNVR and OVF as unsigned uint16_t value = I2cRead16(addr, INA219_REG_BUSVOLTAGE) >> 3; - DEBUG_SENSOR_LOG("Ina219GetBusVoltage_V: BusReg = 0x%04X",value); + DEBUG_SENSOR_LOG("Ina219GetBusVoltage_V: BusReg = 0x%04X (%d)",value, value); // and multiply by LSB raw bus voltage to return bus voltage in volts (LSB=4mV=0.004V) - return value * 0.004; + return (float)value * 0.004; } -/* Not used any more -float Ina219GetCurrent_mA(uint16_t addr) -{ - // 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 - // a cal value even if it's an unfortunate extra step - I2cWrite16(addr, INA219_REG_CALIBRATION, ina219_cal_value); - // Now we can safely read the CURRENT register! - // raw current value (16-bit signed integer, so +-32767) - float value = I2cReadS16(addr, INA219_REG_CURRENT); - value /= ina219_current_divider_ma; - // current value in mA, taking into account the config settings and current LSB - return value; -} -*/ - bool Ina219Read(void) { - for (int i=0; ichan[i].active) { continue; } + uint16_t addr = INA219_ADDRESSES[i]; float bus_voltage_V = Ina219GetBusVoltage_V(addr); float shunt_voltage_mV = Ina219GetShuntVoltage_mV(addr); #ifdef DEBUG_TASMOTA_SENSOR @@ -211,16 +215,15 @@ bool Ina219Read(void) DEBUG_SENSOR_LOG("Ina219Read: bV=%sV, sV=%smV",__ina219_dbg1,__ina219_dbg2); #endif // we return the power-supply-side voltage (as bus_voltage register provides the load-side voltage) - ina219_voltage[i] = bus_voltage_V + (shunt_voltage_mV / 1000); + Ina219Data->chan[i].voltage = bus_voltage_V + (shunt_voltage_mV / 1000); // current is simply calculted from shunt voltage using pre-calculated multiplier - ina219_current[i] = shunt_voltage_mV * ina219_current_multiplier; + Ina219Data->chan[i].current = shunt_voltage_mV * Ina219Data->current_multiplier; #ifdef DEBUG_TASMOTA_SENSOR - dtostrfd(ina219_voltage[i],5,__ina219_dbg1); - dtostrfd(ina219_current[i],5,__ina219_dbg2); + dtostrfd(Ina219Data->chan[i].voltage,5,__ina219_dbg1); + dtostrfd(Ina219Data->chan[i].current,5,__ina219_dbg2); DEBUG_SENSOR_LOG("Ina219Read: V=%sV, I=%smA",__ina219_dbg1,__ina219_dbg2); #endif - ina219_valid[i] = SENSOR_MAX_MISS; - // AddLogMissed(ina219_types, ina219_valid); + Ina219Data->chan[i].valid = SENSOR_MAX_MISS; } return true; } @@ -244,13 +247,20 @@ bool Ina219CommandSensor(void) void Ina219Detect(void) { - for (uint32_t i = 0; i < sizeof(ina219_type); i++) { - uint16_t addr = ina219_addresses[i]; + for (uint32_t i = 0; i < INA219_MAX_COUNT; i++) { + uint16_t addr = INA219_ADDRESSES[i]; if (!I2cSetDevice(addr)) { continue; } + if (!Ina219Data) { + Ina219Data = (struct INA219_Data*)calloc(1,sizeof(struct INA219_Data)); + if (!Ina219Data) { + AddLog(LOG_LEVEL_ERROR,PSTR("INA219: Mem Error")); + return; + } + } if (Ina219SetCalibration(Settings->ina219_mode, addr)) { - I2cSetActiveFound(addr, ina219_types); - ina219_type[i] = 1; - ina219_count++; + I2cSetActiveFound(addr, INA219_TYPE); + Ina219Data->chan[i].active = 1; + Ina219Data->count++; } } } @@ -271,31 +281,31 @@ const char HTTP_SNS_INA219_DATA[] PROGMEM = void Ina219Show(bool json) { int num_found=0; - for (int i=0; ichan[i].active && Ina219Data->chan[i].valid) num_found++; int sensor_num = 0; - for (int i=0; ichan[i].active && !Ina219Data->chan[i].valid) continue; sensor_num++; char voltage[16]; - dtostrfd(ina219_voltage[i], Settings->flag2.voltage_resolution, voltage); + dtostrfd(Ina219Data->chan[i].voltage, Settings->flag2.voltage_resolution, voltage); char current[16]; - dtostrfd(ina219_current[i], Settings->flag2.current_resolution, current); + dtostrfd(Ina219Data->chan[i].current, Settings->flag2.current_resolution, current); char power[16]; - dtostrfd(ina219_voltage[i] * ina219_current[i], Settings->flag2.wattage_resolution, power); + dtostrfd(Ina219Data->chan[i].voltage * Ina219Data->chan[i].current, 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); + snprintf_P(name, sizeof(name), PSTR("%s%c%d"), INA219_TYPE, IndexSeparator(), sensor_num); else - snprintf_P(name, sizeof(name), PSTR("%s"), ina219_types); + snprintf_P(name, sizeof(name), PSTR("%s"), INA219_TYPE); if (json) { ResponseAppend_P(PSTR(",\"%s\":{\"Id\":%02x,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"), - name, ina219_addresses[i], voltage, current, power); + name, INA219_ADDRESSES[i], voltage, current, power); #ifdef USE_DOMOTICZ if (0 == TasmotaGlobal.tele_period) { DomoticzSensor(DZ_VOLTAGE, voltage); @@ -323,7 +333,7 @@ bool Xsns13(uint8_t function) if (FUNC_INIT == function) { Ina219Detect(); } - else if (ina219_count) { + else if (Ina219Data) { switch (function) { case FUNC_COMMAND_SENSOR: if (XSNS_13 == XdrvMailbox.index) {