voltage = INA3221C_BUS_ADC_LSB * (float)(bus_voltage >> 3);
+
+ if (pChannel->shunt > 0.0) {
+ shunt_voltage = I2cReadS16(addr, INA3221_REG_SHUNT_VOLTAGE_CH(channel));
+ DEBUG_SENSOR_LOG(D_INA3221 ":GetShuntVoltage: RegSh[%d:%d](0x%02X) = 0x%04X = %d", device, channel, INA3221_REG_SHUNT_VOLTAGE_CH(channel), shunt_voltage, shunt_voltage);
+ // convert to shunt voltage in V
+ pChannel->current = INA3221C_SHUNT_ADC_LSB * (float)(shunt_voltage >> 3) / pChannel->shunt;
+ } else {
+ pChannel->current = INFINITY;
+ }
+
+ #ifdef DEBUG_TASMOTA_SENSOR
+ dtostrfd(pChannel->voltage,5,_ina3221_dbg1);
+ dtostrfd(pChannel->current,5,_ina3221_dbg2);
+ DEBUG_SENSOR_LOG(D_INA3221 ":Read[%d:%d]: V=%sV, I=%sA", device, channel, _ina3221_dbg1, _ina3221_dbg2);
+ #endif
+
+ return true;
+}
+
+/*********************************************************************************************\
+ * Command Sensor
+\*********************************************************************************************/
+
+bool Ina3221CmndSensor(void)
+{
+ int argc = ArgC();
+ if(argc != 1 && argc != 4) {
+ return false;
+ }
+
+ char argument[XdrvMailbox.data_len+FLOATSZ];
+ uint32_t device = atoi(ArgV(argument,1)) -1;
+ if (device >= INA3221_MAX_COUNT || !Ina3221Data[device].i2caddr) {
+ DEBUG_SENSOR_LOG(D_INA3221 ":Sensor: invalid device %d", device+1);
+ return false;
+ }
+
+ if (argc > 1) {
+ for (int channel = 0 ; channel < INA3221_NB_CHAN ; channel++) {
+ float shunt = CharToFloat(ArgV(argument,2+channel));
+ Ina3221SetShunt(device, channel, shunt);
+ }
+ }
+ Response_P(INA3221_SENSORCMND_START, XSNS_100, device +1, Ina3221Data[device].i2caddr);
+ for (int channel = 0 ; channel < INA3221_NB_CHAN ; channel++ ) {
+ dtostrfd(Ina3221Data[device].chan[channel].shunt,5,argument);
+ ResponseAppend_P(PSTR("%s%c"), argument, ((channel < (INA3221_NB_CHAN-1))?',':'\0'));
+ }
+ ResponseAppend_P(INA3221_SENSORCMND_END);
+
+ return true;
+}
+
+/********************************************************************************************/
+
+void Ina3221Detect(void)
+{
+ _ina3221_current_device = 0;
+ Ina3221count = 0;
+ for (uint32_t i = 0; i < INA3221_MAX_COUNT; i++) {
+ uint16_t addr = INA3221_ADDRESS(i);
+ if (!I2cSetDevice(addr)) { continue; }
+ if (!Ina3221Data) {
+ Ina3221Data = (struct INA3221_Data*)calloc(INA3221_MAX_COUNT,sizeof(struct INA3221_Data));
+ if (!Ina3221Data) {
+ AddLog(LOG_LEVEL_ERROR,PSTR(D_INA3221 ": Mem allocation error"));
+ return;
+ }
+ }
+ if (Ina3221SetConfig(addr)) {
+ I2cSetActiveFound(addr, INA3221_TYPE);
+ Ina3221Data[Ina3221count].i2caddr = addr;
+ Ina3221Data[Ina3221count].enabled_chan = 0;
+ Ina3221Data[Ina3221count].chan[0].shunt = \
+ Ina3221Data[Ina3221count].chan[1].shunt = \
+ Ina3221Data[Ina3221count].chan[2].shunt = 0.0;
+ Ina3221count++;
+ }
+ }
+ if (!Ina3221count && Ina3221Data) {
+ free(Ina3221Data);
+ Ina3221Data = nullptr;
+ }
+}
+
+void Ina3221Every250ms(void)
+{
+ DEBUG_SENSOR_LOG(PSTR(D_INA3221 ": cur:%d, en:%d"), _ina3221_current_device, Ina3221Data[_ina3221_current_device].enabled_chan);
+ uint8_t enabled_chan = Ina3221Data[_ina3221_current_device].enabled_chan;
+ for (int chan = 0 ; enabled_chan ; chan++, enabled_chan>>=1) {
+ if (0x01 & enabled_chan)
+ Ina3221Read(_ina3221_current_device, chan);
+ }
+
+ if (++_ina3221_current_device >= INA3221_MAX_COUNT)
+ _ina3221_current_device = 0;
+}
+
+#ifdef USE_WEBSERVER
+const char HTTP_SNS_INA3221_HEADER[] PROGMEM =
+ "{s}" D_INA3221 " | " D_VOLTAGE " | | " D_CURRENT " | | " D_POWERUSAGE " {e}";
+
+const char HTTP_SNS_INA3221_DATA[] PROGMEM =
+ "{s}%s | | %s " D_UNIT_VOLT " | | %s " D_UNIT_AMPERE " | | %s " D_UNIT_WATT " {e}";
+#endif // USE_WEBSERVER
+
+void Ina3221Show(bool json)
+{
+ char name[FLOATSZ];
+ char temp[FLOATSZ];
+ char voltage[3*FLOATSZ+3];
+ char current[3*FLOATSZ+3];
+ char power[3*FLOATSZ+3];
+
+ if (json) {
+ // data
+ for (int device=0 ; device < Ina3221count ; device++) {
+ uint8_t enabled_chan = Ina3221Data[device].enabled_chan;
+ if (!enabled_chan) continue;
+
+ if (Ina3221count > 1)
+ snprintf_P(name, sizeof(name), PSTR("%s%c%d"), INA3221_TYPE, IndexSeparator(), device +1);
+ else
+ snprintf_P(name, sizeof(name), PSTR("%s"), INA3221_TYPE);
+ voltage[0] = current[0] = power[0] = '\0';
+
+ for (int chan=0 ; enabled_chan ; chan++, enabled_chan>>=1) {
+ if (0x01 & enabled_chan) {
+ dtostrfd(Ina3221Data[device].chan[chan].voltage, Settings->flag2.voltage_resolution, temp);
+ strncat(voltage, temp, sizeof(voltage));
+ dtostrfd(Ina3221Data[device].chan[chan].current, Settings->flag2.current_resolution, temp);
+ strncat(current, temp, sizeof(voltage));
+ dtostrfd(Ina3221Data[device].chan[chan].voltage * Ina3221Data[device].chan[chan].current, Settings->flag2.wattage_resolution, temp);
+ strncat(power, temp, sizeof(voltage));
+ } //if enabled
+ else {
+ strncat(voltage, "null", sizeof(voltage));
+ strncat(current, "null", sizeof(voltage));
+ strncat(power, "null", sizeof(voltage));
+ }
+ if (0xFE & enabled_chan) {
+ strncat(voltage, ",", sizeof(voltage));
+ strncat(current, ",", sizeof(voltage));
+ strncat(power, ",", sizeof(voltage));
+ }
+ } // for channel
+ ResponseAppend_P(PSTR(",\"%s\":{\"Id\":\"0x%02x\",\"" D_JSON_VOLTAGE "\":[%s],\"" D_JSON_CURRENT "\":[%s],\"" D_JSON_POWERUSAGE "\":[%s]}"),
+ name, Ina3221Data[device].i2caddr, voltage, current, power);
+#ifdef USE_DOMOTICZ
+ if (0 == TasmotaGlobal.tele_period) {
+ DomoticzSensor(DZ_VOLTAGE, voltage);
+ DomoticzSensor(DZ_CURRENT, current);
+ }
+#endif // USE_DOMOTICZ
+ } // for device
+ } // if json
+#ifdef USE_WEBSERVER
+ else {
+ // header
+ WSContentSend_PD(HTTP_SNS_INA3221_HEADER);
+ // data
+ for (int device=0 ; device < Ina3221count ; device++) {
+ uint8_t enabled_chan = Ina3221Data[device].enabled_chan;
+ for (int chan=0 ; enabled_chan ; chan++, enabled_chan>>=1) {
+ if (0x01 & enabled_chan) {
+ if (Ina3221count > 1)
+ snprintf_P(name, sizeof(name), PSTR("%s%c%d:%d"), INA3221_TYPE, IndexSeparator(), device +1, chan);
+ else
+ snprintf_P(name, sizeof(name), PSTR("%s:%d"), INA3221_TYPE, chan);
+ dtostrfd(Ina3221Data[device].chan[chan].voltage, Settings->flag2.voltage_resolution, voltage);
+ dtostrfd(Ina3221Data[device].chan[chan].current, Settings->flag2.current_resolution, current);
+ dtostrfd(Ina3221Data[device].chan[chan].voltage * Ina3221Data[device].chan[chan].current, Settings->flag2.wattage_resolution, power);
+ WSContentSend_PD(HTTP_SNS_INA3221_DATA, name, voltage, current, power);
+ } // if active
+ } // for channel
+ } // for device
+ }
+#endif
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xsns100(uint8_t function)
+{
+ if (!I2cEnabled(XI2C_72)) { return false; }
+
+ bool result = false;
+
+ if (FUNC_INIT == function) {
+ Ina3221Detect();
+ }
+ else if (Ina3221Data) {
+ switch (function) {
+ case FUNC_COMMAND_SENSOR:
+ if (XSNS_100 == XdrvMailbox.index) {
+ result = Ina3221CmndSensor();
+ }
+ break;
+ case FUNC_EVERY_250_MSECOND:
+ Ina3221Every250ms();
+ break;
+ case FUNC_JSON_APPEND:
+ Ina3221Show(1);
+ break;
+ #ifdef USE_WEBSERVER
+ case FUNC_WEB_SENSOR:
+ Ina3221Show(0);
+ break;
+ #endif // USE_WEBSERVER
+ #ifdef USE_DEEPSLEEP
+ case FUNC_SAVE_BEFORE_RESTART:
+ for (uint8_t device; device < Ina3221count ; device++)
+ Ina3221PowerDown(device);
+ break;
+ #endif // USE_DEEPSLEEP }
+ }
+ }
+ return result;
+}
+
+#endif // USE_INA3221
+#endif // USE_I2C
|