From 746b5389be72e573089a462cf487b7c6191d5f08 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Sun, 9 Oct 2022 19:11:43 +0200 Subject: [PATCH] driver ina3221, take 1 --- I2CDEVICES.md | 201 ++++---- .../tasmota_xsns_sensor/xsns_100_ina3221.ino | 459 ++++++++++++++++++ 2 files changed, 560 insertions(+), 100 deletions(-) create mode 100644 tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 90be957ef..d3b2cd418 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -6,103 +6,104 @@ Using command ``I2cDriver`` individual drivers can be enabled or disabled at run ## Supported I2C devices The following table lists the supported I2C devices -Index | Define | Driver | Device | Address(es) | Description -------|---------------------|---------|----------|-------------|----------------------------------------------- - 1 | USE_PCA9685 | xdrv_15 | PCA9685 | 0x40 - 0x47 | 16-channel 12-bit pwm driver - 2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | 8-bit I/O expander - 2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | 8-bit I/O expander - 3 | USE_DISPLAY_LCD | xdsp_01 | | 0x27, 0x3F | LCD display - 4 | USE_DISPLAY_SSD1306 | xdsp_02 | SSD1306 | 0x3C - 0x3D | Oled display - 5 | USE_DISPLAY_MATRIX | xdsp_03 | HT16K33 | 0x70 - 0x77 | 8x8 led matrix - 6 | USE_DISPLAY_SH1106 | xdsp_07 | SH1106 | 0x3C - 0x3D | Oled display - 7 | USE_ADE7953 | xnrg_07 | ADE7953 | 0x38 | Energy monitor - 8 | USE_SHT | xsns_07 | SHT1X | Any | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | HTU21 | 0x40 | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | SI7013 | 0x40 | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | SI7020 | 0x40 | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | SI7021 | 0x40 | Temperature and Humidity sensor - 10 | USE_BMP | xsns_09 | BMP085 | 0x76 - 0x77 | Pressure and temperature sensor - 10 | USE_BMP | xsns_09 | BMP180 | 0x76 - 0x77 | Pressure and temperature sensor - 10 | USE_BMP | xsns_09 | BMP280 | 0x76 - 0x77 | Pressure and temperature sensor - 10 | USE_BMP | xsns_09 | BME280 | 0x76 - 0x77 | Pressure, temperature and humidity sensor - 10 | USE_BMP | xsns_09 | BME680 | 0x76 - 0x77 | Pressure, temperature, humidity and gas sensor - 11 | USE_BH1750 | xsns_10 | BH1750 | 0x23, 0x5C | Ambient light intensity sensor - 12 | USE_VEML6070 | xsns_11 | VEML6070 | 0x38 - 0x39 | Ultra violet light intensity sensor - 13 | USE_ADS1115 | xsns_12 | ADS1115 | 0x48 - 0x4B | 4-channel 16-bit A/D converter - 14 | USE_INA219 | xsns_13 | INA219 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor - 15 | USE_SHT3X | xsns_14 | SHT3X | 0x44 - 0x45 | Temperature and Humidity sensor - 15 | USE_SHT3X | xsns_14 | SHT4X | 0x44 - 0x45 | Temperature and Humidity sensor - 15 | USE_SHT3X | xsns_14 | SHTCX | 0x70 | Temperature and Humidity sensor - 16 | USE_TSL2561 | xsns_16 | TSL2561 | 0x29, 0x39, 0x49 | Light intensity sensor - 17 | USE_MGS | xsns_19 | Grove | 0x04 | Multichannel gas sensor - 18 | USE_SGP30 | xsns_21 | SGP30 | 0x58 | Gas (TVOC) and air quality sensor - 19 | USE_SI1145 | xsns_24 | SI1145 | 0x60 | Ultra violet index and light sensor - 19 | USE_SI1145 | xsns_24 | SI1146 | 0x60 | Ultra violet index and light sensor - 19 | USE_SI1145 | xsns_24 | SI1147 | 0x60 | Ultra violet index and light sensor - 20 | USE_LM75AD | xsns_26 | LM75AD | 0x48 - 0x4F | Temperature sensor - 21 | USE_APDS9960 | xsns_27 | APDS9960 | 0x39 | Proximity ambient light RGB and gesture sensor - 22 | USE_MCP230xx | xsns_29 | MCP23008 | 0x20 - 0x26 | 8-bit I/O expander - 22 | USE_MCP230xx | xsns_29 | MCP23017 | 0x20 - 0x26 | 16-bit I/O expander - 23 | USE_MPR121 | xsns_30 | MPR121 | 0x5A - 0x5D | Proximity capacitive touch sensor - 24 | USE_CCS811 | xsns_31 | CCS811 | 0x5A | Gas (TVOC) and air quality sensor - 25 | USE_MPU6050 | xsns_32 | MPU6050 | 0x68 - 0x69 | 3-axis gyroscope and temperature sensor - 26 | USE_DS3231 | xsns_33 | DS3231 | 0x68 | Real time clock - 27 | USE_MGC3130 | xsns_36 | MGC3130 | 0x42 | Electric field sensor - 28 | USE_MAX44009 | xsns_41 | MAX44009 | 0x4A - 0x4B | Ambient light intensity sensor - 29 | USE_SCD30 | xsns_42 | SCD30 | 0x61 | CO2 sensor - 30 | USE_SPS30 | xsns_44 | SPS30 | 0x69 | Particle sensor - 31 | USE_VL53L0X | xsns_45 | VL53L0X | 0x29 | Time-of-flight (ToF) distance sensor - 32 | USE_MLX90614 | xsns_46 | MLX90614 | 0x5A | Infra red temperature sensor - 33 | USE_CHIRP | xsns_48 | CHIRP | 0x20 | Soil moisture sensor - 34 | USE_PAJ7620 | xsns_50 | PAJ7620 | 0x73 | Gesture sensor - 35 | USE_INA226 | xsns_54 | INA226 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor - 36 | USE_HIH6 | xsns_55 | HIH6130 | 0x27 | Temperature and Humidity sensor - 37 | USE_24C256 | xdrv_10 | 24C256 | 0x50 | Scripter EEPROM storage - 38 | USE_DISPLAY_ILI9488 | xdsp_08 | FT6236 | 0x38 | Touch panel controller - 39 | USE_DISPLAY_RA8876 | xdsp_10 | FT5316 | 0x38 | Touch panel controller - 40 | USE_TSL2591 | xsns_57 | TLS2591 | 0x29 | Light intensity sensor - 41 | USE_DHT12 | xsns_58 | DHT12 | 0x5C | Temperature and humidity sensor - 42 | USE_DS1624 | xsns_59 | DS1621 | 0x48 - 0x4F | Temperature sensor - 42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor - 43 | USE_AHT1x | xsns_63 | AHT10/15 | 0x38 - 0x39 | Temperature and humidity sensor - 43 | USE_AHT2x | xsns_63 | AHT20 | 0x38 | Temperature and humidity sensor - 43 | USE_AHT2x | xsns_63 | AM2301B | 0x38 | Temperature and humidity sensor - 44 | USE_WEMOS_MOTOR_V1 | xdrv_34 | | 0x2D - 0x30 | WEMOS motor shield v1.0.0 (6612FNG) - 45 | USE_HDC1080 | xsns_65 | HDC1080 | 0x40 | Temperature and Humidity sensor - 46 | USE_IAQ | xsns_66 | IAQ | 0x5a | Air quality sensor - 47 | USE_DISPLAY_SEVENSEG| xdsp_11 | HT16K33 | 0x70 - 0x77 | Seven segment LED - 48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor - 49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor - 50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor - 51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor - 52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor - 53 | USE_MLX90640 | xdrv_43 | MLX90640 | 0x33 | IR array temperature sensor - 54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor - 55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH sensor - 55 | USE_EZOORP | xsns_78 | EZOORP | 0x61 - 0x70 | ORP sensor - 55 | USE_EZORTD | xsns_78 | EZORTD | 0x61 - 0x70 | Temperature sensor - 55 | USE_EZOHUM | xsns_78 | EZOHUM | 0x61 - 0x70 | Humidity sensor - 55 | USE_EZOEC | xsns_78 | EZOEC | 0x61 - 0x70 | Electric conductivity sensor - 55 | USE_EZOCO2 | xsns_78 | EZOCO2 | 0x61 - 0x70 | CO2 sensor - 55 | USE_EZOO2 | xsns_78 | EZOO2 | 0x61 - 0x70 | O2 sensor - 55 | USE_EZOPRS | xsns_78 | EZOPRS | 0x61 - 0x70 | Pressure sensor - 55 | USE_EZOFLO | xsns_78 | EZOFLO | 0x61 - 0x70 | Flow meter sensor - 55 | USE_EZODO | xsns_78 | EZODO | 0x61 - 0x70 | Disolved Oxygen sensor - 55 | USE_EZORGB | xsns_78 | EZORGB | 0x61 - 0x70 | Color sensor - 55 | USE_EZOPMP | xsns_78 | EZOPMP | 0x61 - 0x70 | Peristaltic Pump - 56 | USE_SEESAW_SOIL | xsns_81 | SEESOIL | 0x36 - 0x39 | Adafruit seesaw soil moisture sensor - 57 | USE_TOF10120 | xsns_84 | TOF10120 | 0x52 | Time-of-flight (ToF) distance sensor - 58 | USE_MPU_ACCEL | xsns_85 | MPU_ACCEL| 0x68 | MPU6886/MPU9250 6-axis MotionTracking sensor from M5Stack - 59 | USE_BM8563 | xdrv_56 | BM8563 | 0x51 | BM8563 RTC from M5Stack - 60 | USE_AM2320 | xsns_88 | AM2320 | 0x5C | Temperature and Humidity sensor - 61 | USE_T67XX | xsns_89 | T67XX | 0x15 | CO2 sensor - 62 | USE_SCD40 | xsns_92 | SCD40 | 0x62 | CO2 sensor Sensirion SCD40/SCD41 - 63 | USE_HM330X | xsns_93 | HM330X | 0x40 | Particule sensor - 64 | USE_HDC2010 | xsns_94 | HDC2010 | 0x40 | Temperature and Humidity sensor - 65 | USE_ADE7880 | xnrg_23 | ADE7880 | 0x38 | Energy monitor - 66 | USE_PCF85363 | xsns_99 | PCF85363 | 0x51 | Real time clock - 67 | USE_DS3502 | xdrv_61 | DS3502 | 0x28 - 0x2B | Digital potentiometer - 68 | USE_HYT | xsns_97 | HYTxxx | 0x28 | Temperature and Humidity sensor - 69 | USE_SGP40 | xsns_98 | SGP40 | 0x59 | Gas (TVOC) and air quality - 70 | USE_LUXV30B | xsns_99 | LUXV30B | 0x4A | DFRobot SEN0390 V30B lux sensor - 71 | USE_QMC5883L | xsns_33 | QMC5883L | 0x0D | Magnetic Field Sensor +Index | Define | Driver | Device | Address(es) | Description +------|---------------------|----------|----------|-------------|----------------------------------------------- + 1 | USE_PCA9685 | xdrv_15 | PCA9685 | 0x40 - 0x47 | 16-channel 12-bit pwm driver + 2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | 8-bit I/O expander + 2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | 8-bit I/O expander + 3 | USE_DISPLAY_LCD | xdsp_01 | | 0x27, 0x3F | LCD display + 4 | USE_DISPLAY_SSD1306 | xdsp_02 | SSD1306 | 0x3C - 0x3D | Oled display + 5 | USE_DISPLAY_MATRIX | xdsp_03 | HT16K33 | 0x70 - 0x77 | 8x8 led matrix + 6 | USE_DISPLAY_SH1106 | xdsp_07 | SH1106 | 0x3C - 0x3D | Oled display + 7 | USE_ADE7953 | xnrg_07 | ADE7953 | 0x38 | Energy monitor + 8 | USE_SHT | xsns_07 | SHT1X | Any | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | HTU21 | 0x40 | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | SI7013 | 0x40 | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | SI7020 | 0x40 | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | SI7021 | 0x40 | Temperature and Humidity sensor + 10 | USE_BMP | xsns_09 | BMP085 | 0x76 - 0x77 | Pressure and temperature sensor + 10 | USE_BMP | xsns_09 | BMP180 | 0x76 - 0x77 | Pressure and temperature sensor + 10 | USE_BMP | xsns_09 | BMP280 | 0x76 - 0x77 | Pressure and temperature sensor + 10 | USE_BMP | xsns_09 | BME280 | 0x76 - 0x77 | Pressure, temperature and humidity sensor + 10 | USE_BMP | xsns_09 | BME680 | 0x76 - 0x77 | Pressure, temperature, humidity and gas sensor + 11 | USE_BH1750 | xsns_10 | BH1750 | 0x23, 0x5C | Ambient light intensity sensor + 12 | USE_VEML6070 | xsns_11 | VEML6070 | 0x38 - 0x39 | Ultra violet light intensity sensor + 13 | USE_ADS1115 | xsns_12 | ADS1115 | 0x48 - 0x4B | 4-channel 16-bit A/D converter + 14 | USE_INA219 | xsns_13 | INA219 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor + 15 | USE_SHT3X | xsns_14 | SHT3X | 0x44 - 0x45 | Temperature and Humidity sensor + 15 | USE_SHT3X | xsns_14 | SHT4X | 0x44 - 0x45 | Temperature and Humidity sensor + 15 | USE_SHT3X | xsns_14 | SHTCX | 0x70 | Temperature and Humidity sensor + 16 | USE_TSL2561 | xsns_16 | TSL2561 | 0x29, 0x39, 0x49 | Light intensity sensor + 17 | USE_MGS | xsns_19 | Grove | 0x04 | Multichannel gas sensor + 18 | USE_SGP30 | xsns_21 | SGP30 | 0x58 | Gas (TVOC) and air quality sensor + 19 | USE_SI1145 | xsns_24 | SI1145 | 0x60 | Ultra violet index and light sensor + 19 | USE_SI1145 | xsns_24 | SI1146 | 0x60 | Ultra violet index and light sensor + 19 | USE_SI1145 | xsns_24 | SI1147 | 0x60 | Ultra violet index and light sensor + 20 | USE_LM75AD | xsns_26 | LM75AD | 0x48 - 0x4F | Temperature sensor + 21 | USE_APDS9960 | xsns_27 | APDS9960 | 0x39 | Proximity ambient light RGB and gesture sensor + 22 | USE_MCP230xx | xsns_29 | MCP23008 | 0x20 - 0x26 | 8-bit I/O expander + 22 | USE_MCP230xx | xsns_29 | MCP23017 | 0x20 - 0x26 | 16-bit I/O expander + 23 | USE_MPR121 | xsns_30 | MPR121 | 0x5A - 0x5D | Proximity capacitive touch sensor + 24 | USE_CCS811 | xsns_31 | CCS811 | 0x5A | Gas (TVOC) and air quality sensor + 25 | USE_MPU6050 | xsns_32 | MPU6050 | 0x68 - 0x69 | 3-axis gyroscope and temperature sensor + 26 | USE_DS3231 | xsns_33 | DS3231 | 0x68 | Real time clock + 27 | USE_MGC3130 | xsns_36 | MGC3130 | 0x42 | Electric field sensor + 28 | USE_MAX44009 | xsns_41 | MAX44009 | 0x4A - 0x4B | Ambient light intensity sensor + 29 | USE_SCD30 | xsns_42 | SCD30 | 0x61 | CO2 sensor + 30 | USE_SPS30 | xsns_44 | SPS30 | 0x69 | Particle sensor + 31 | USE_VL53L0X | xsns_45 | VL53L0X | 0x29 | Time-of-flight (ToF) distance sensor + 32 | USE_MLX90614 | xsns_46 | MLX90614 | 0x5A | Infra red temperature sensor + 33 | USE_CHIRP | xsns_48 | CHIRP | 0x20 | Soil moisture sensor + 34 | USE_PAJ7620 | xsns_50 | PAJ7620 | 0x73 | Gesture sensor + 35 | USE_INA226 | xsns_54 | INA226 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor + 36 | USE_HIH6 | xsns_55 | HIH6130 | 0x27 | Temperature and Humidity sensor + 37 | USE_24C256 | xdrv_10 | 24C256 | 0x50 | Scripter EEPROM storage + 38 | USE_DISPLAY_ILI9488 | xdsp_08 | FT6236 | 0x38 | Touch panel controller + 39 | USE_DISPLAY_RA8876 | xdsp_10 | FT5316 | 0x38 | Touch panel controller + 40 | USE_TSL2591 | xsns_57 | TLS2591 | 0x29 | Light intensity sensor + 41 | USE_DHT12 | xsns_58 | DHT12 | 0x5C | Temperature and humidity sensor + 42 | USE_DS1624 | xsns_59 | DS1621 | 0x48 - 0x4F | Temperature sensor + 42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor + 43 | USE_AHT1x | xsns_63 | AHT10/15 | 0x38 - 0x39 | Temperature and humidity sensor + 43 | USE_AHT2x | xsns_63 | AHT20 | 0x38 | Temperature and humidity sensor + 43 | USE_AHT2x | xsns_63 | AM2301B | 0x38 | Temperature and humidity sensor + 44 | USE_WEMOS_MOTOR_V1 | xdrv_34 | | 0x2D - 0x30 | WEMOS motor shield v1.0.0 (6612FNG) + 45 | USE_HDC1080 | xsns_65 | HDC1080 | 0x40 | Temperature and Humidity sensor + 46 | USE_IAQ | xsns_66 | IAQ | 0x5a | Air quality sensor + 47 | USE_DISPLAY_SEVENSEG| xdsp_11 | HT16K33 | 0x70 - 0x77 | Seven segment LED + 48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor + 49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor + 50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor + 51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor + 52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor + 53 | USE_MLX90640 | xdrv_43 | MLX90640 | 0x33 | IR array temperature sensor + 54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor + 55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH sensor + 55 | USE_EZOORP | xsns_78 | EZOORP | 0x61 - 0x70 | ORP sensor + 55 | USE_EZORTD | xsns_78 | EZORTD | 0x61 - 0x70 | Temperature sensor + 55 | USE_EZOHUM | xsns_78 | EZOHUM | 0x61 - 0x70 | Humidity sensor + 55 | USE_EZOEC | xsns_78 | EZOEC | 0x61 - 0x70 | Electric conductivity sensor + 55 | USE_EZOCO2 | xsns_78 | EZOCO2 | 0x61 - 0x70 | CO2 sensor + 55 | USE_EZOO2 | xsns_78 | EZOO2 | 0x61 - 0x70 | O2 sensor + 55 | USE_EZOPRS | xsns_78 | EZOPRS | 0x61 - 0x70 | Pressure sensor + 55 | USE_EZOFLO | xsns_78 | EZOFLO | 0x61 - 0x70 | Flow meter sensor + 55 | USE_EZODO | xsns_78 | EZODO | 0x61 - 0x70 | Disolved Oxygen sensor + 55 | USE_EZORGB | xsns_78 | EZORGB | 0x61 - 0x70 | Color sensor + 55 | USE_EZOPMP | xsns_78 | EZOPMP | 0x61 - 0x70 | Peristaltic Pump + 56 | USE_SEESAW_SOIL | xsns_81 | SEESOIL | 0x36 - 0x39 | Adafruit seesaw soil moisture sensor + 57 | USE_TOF10120 | xsns_84 | TOF10120 | 0x52 | Time-of-flight (ToF) distance sensor + 58 | USE_MPU_ACCEL | xsns_85 | MPU_ACCEL| 0x68 | MPU6886/MPU9250 6-axis MotionTracking sensor from M5Stac k + 59 | USE_BM8563 | xdrv_56 | BM8563 | 0x51 | BM8563 RTC from M5Stack + 60 | USE_AM2320 | xsns_88 | AM2320 | 0x5C | Temperature and Humidity sensor + 61 | USE_T67XX | xsns_89 | T67XX | 0x15 | CO2 sensor + 62 | USE_SCD40 | xsns_92 | SCD40 | 0x62 | CO2 sensor Sensirion SCD40/SCD41 + 63 | USE_HM330X | xsns_93 | HM330X | 0x40 | Particule sensor + 64 | USE_HDC2010 | xsns_94 | HDC2010 | 0x40 | Temperature and Humidity sensor + 65 | USE_ADE7880 | xnrg_23 | ADE7880 | 0x38 | Energy monitor + 66 | USE_PCF85363 | xsns_99 | PCF85363 | 0x51 | Real time clock + 67 | USE_DS3502 | xdrv_61 | DS3502 | 0x28 - 0x2B | Digital potentiometer + 68 | USE_HYT | xsns_97 | HYTxxx | 0x28 | Temperature and Humidity sensor + 69 | USE_SGP40 | xsns_98 | SGP40 | 0x59 | Gas (TVOC) and air quality + 70 | USE_LUXV30B | xsns_99 | LUXV30B | 0x4A | DFRobot SEN0390 V30B lux sensor + 71 | USE_QMC5883L | xsns_33 | QMC5883L | 0x0D | Magnetic Field Sensor + 72 | USE_INA3221 | xsns_100 | INA3221 | 0x40-0x43 | 3-channels Voltage and Current sensor diff --git a/tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino b/tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino new file mode 100644 index 000000000..1c7bc3d52 --- /dev/null +++ b/tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino @@ -0,0 +1,459 @@ +/* + xsns_100_ina3221.ino - INA3221 3-channels Current Sensor support for Tasmota + + Copyright (C) 2021 Barbudor and Theo Arends + Based on Barbudor's CircuitPython_INA3221 + + 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_INA3221 +/*********************************************************************************************\ + * INA3221 - 3 channels High-side DC voltage and current measurment + * https://www.ti.com/product/INA3221 + * + * Up to 4 devices can be connected (12 channels) + * I2C Address: 0x40, 0x41, 0x43 or 0x43 + * + * IMPORTANT INFORMATION + * By default the driver is enabled to support up to 4 INA3221 from hte above addresse + * If you want to enable less addresses in order to use other I2C chip on those addresses you + * can define in your user_config_override.h the following: + * #define INA3221_MAX_COUNT the max number of INA3221 to support + * #define INA3221_ADDRESS1 the I2C address of the 1st INA3221 + * For example to support only 2 INA3221 at addresses 0x41 and 0x42 you can use: + * #define INA3221_MAX_COUNT 2 + * #define INA3221_ADDRESS1 0x41 + * That would leave 0x40 and 0x42 for other devices + * Nevertheless, hte driver tries to identifiy if the chip as an address is a IN3221 +\*********************************************************************************************/ + +#define XSNS_100 100 +#define XI2C_72 72 // See I2CDEVICES.md + +#ifndef INA3221_MAX_COUNT +#define INA3221_MAX_COUNT 4 +#endif +#if (INA3221_MAX_COUNT > 4) +#error "**** INA3221_MAX_COUNT can't be greater than 4 ****" +#endif + +#ifndef INA3221_ADDRESS1 +#define INA3221_ADDRESS1 (0x40) // 1000000 (A0=GND) +#define INA3221_ADDRESS2 (0x41) // 1000000 (A0=VS) +#define INA3221_ADDRESS3 (0x42) // 1000010 (A0=SDA) +#define INA3221_ADDRESS4 (0x43) // 1000011 (A0=SCL) +#endif +#define INA3221_ADDRESS(index) (INA3221_ADDRESS1+(index)) +#if ((INA3221_ADDRESS1 + INA3221_MAX_COUNT) > 0x44) +#error "**** INA3221 bad combination for ADDRESS1 and MAX_COUNT ****" +#endif + +#define INA3221_NB_CHAN (3) + +// Config register - ch : 0..2 +#define INA3221_REG_CONFIG (0x00) + +#define INA3221_RESET (0x8000) +#define INA3221_ENABLE_MASK (0x7000) +#define INA3221_ENABLE_CH(ch) (0x4000>>(ch)) // default: set + +#define INA3221_AVERAGING_MASK (0x0E00) +#define INA3221_AVERAGING_NONE (0x0000) // 1 sample, default +#define INA3221_AVERAGING_4_SAMPLES (0x0200) +#define INA3221_AVERAGING_16_SAMPLES (0x0400) +#define INA3221_AVERAGING_64_SAMPLES (0x0600) +#define INA3221_AVERAGING_128_SAMPLES (0x0800) +#define INA3221_AVERAGING_256_SAMPLES (0x0A00) +#define INA3221_AVERAGING_512_SAMPLES (0x0C00) +#define INA3221_AVERAGING_1024_SAMPLES (0x0E00) + +#define INA3221_VBUS_CONV_TIME_MASK (0x01C0) +#define INA3221_VBUS_CONV_TIME_140US (0x0000) +#define INA3221_VBUS_CONV_TIME_204US (0x0040) +#define INA3221_VBUS_CONV_TIME_332US (0x0080) +#define INA3221_VBUS_CONV_TIME_588US (0x00C0) +#define INA3221_VBUS_CONV_TIME_1MS (0x0100) // 1.1ms, default +#define INA3221_VBUS_CONV_TIME_2MS (0x0140) // 2.116ms +#define INA3221_VBUS_CONV_TIME_4MS (0x0180) // 4.156ms +#define INA3221_VBUS_CONV_TIME_8MS (0x01C0) // 8.244ms + +#define INA3221_SHUNT_CONV_TIME_MASK (0x0038) +#define INA3221_SHUNT_CONV_TIME_140US (0x0000) +#define INA3221_SHUNT_CONV_TIME_204US (0x0008) +#define INA3221_SHUNT_CONV_TIME_332US (0x0010) +#define INA3221_SHUNT_CONV_TIME_588US (0x0018) +#define INA3221_SHUNT_CONV_TIME_1MS (0x0020) // 1.1ms, default +#define INA3221_SHUNT_CONV_TIME_2MS (0x0028) // 2.116ms +#define INA3221_SHUNT_CONV_TIME_4MS (0x0030) // 4.156ms +#define INA3221_SHUNT_CONV_TIME_8MS (0x0038) // 8.244ms + +#define INA3221_MODE_MASK (0x0007) +#define INA3221_MODE_POWER_DOWN (0x0000) +#define INA3221_MODE_SHUNT_VOLTAGE_TRIGGERED (0x0001) +#define INA3221_MODE_BUS_VOLTAGE_TRIGGERED (0x0002) +#define INA3221_MODE_SHUNT_AND_BUS_TRIGGERED (0x0003) +#define INA3221_MODE_POWER_DOWN2 (0x0004) +#define INA3221_MODE_SHUNT_VOLTAGE_CONTINUOUS (0x0005) +#define INA3221_MODE_BUS_VOLTAGE_CONTINUOUS (0x0006) +#define INA3221_MODE_SHUNT_AND_BUS_CONTINOUS (0x0007) + +// Other registers - ch = 0..2 +#define INA3221_REG_SHUNT_VOLTAGE_CH(ch) (0x01+((ch)<<1)) +#define INA3221_REG_BUS_VOLTAGE_CH(ch) (0x02+((ch)<<1)) +#define INA3221_REG_CRITICAL_ALERT_LIMIT_CH(ch) (0x07+((ch)<<1)) +#define INA3221_REG_WARNING_ALERT_LIMIT_CH(ch) (0x08+((ch)<<1)) +#define INA3221_REG_SHUNT_VOLTAGE_SUM (0x0D) +#define INA3221_REG_SHUNT_VOLTAGE_SUM_LIMIT (0x0E) + +// Mask/enable register - ch = 1..3 +#define INA3221_REG_MASK_ENABLE (0x0F) +#define INA3221_SUM_CONTROL_CH(ch) (0x4000>>((ch)-1)) +#define INA3221_WARNING_LATCH_ENABLE (0x0800) +#define INA3221_CRITICAL_LATCH_ENABLE (0x0400) +#define INA3221_CRITICAL_FLAG_CH(ch) (0x0200>>((ch)-1)) +#define INA3221_SUM_ALERT_FLAG (0x0040) +#define INA3221_WARNING_FLAG_CH(ch) (0x0020>>((ch)-1)) +#define INA3221_POWER_ALERT_FLAG (0x0004) +#define INA3221_TIMING_ALERT_FLAG (0x0002) +#define INA3221_CONV_READY_FLAG (0x0001) + +// Other registers +#define INA3221_REG_POWER_VALID_UPPER_LIMIT (0x10) +#define INA3221_REG_POWER_VALID_LOWER_LIMIT (0x11) +#define INA3221_REG_MANUFACTURER_ID (0xFE) +#define INA3221_REG_DIE_ID (0xFF) + +// Constants for manufacturer and device ID +#define INA3221_MANUFACTURER_ID (0x5449) // "TI" +#define INA3221_DIE_ID (0x3220) + +// General constants +#define INA3221C_BUS_ADC_LSB (0.008) // VBus ADC LSB is 8mV +#define INA3221C_SHUNT_ADC_LSB (0.00004) // VShunt ADC LSB is 40µV +#define INA3221_DEFAULT_SHUNT_RESISTOR (0.1) + +#ifdef DEBUG_TASMOTA_SENSOR +// temporary strings for floating point in debug messages +char _ina3221_dbg1[FLOATSZ]; +char _ina3221_dbg2[FLOATSZ]; +#endif + +const char INA3221_SENSORCMND_START[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":{\"idx\":%d,\"addr\":\"0x%02X\",\"rshunt\":["; +const char INA3221_SENSORCMND_END[] PROGMEM = "]}}"; + +struct INA3221_Channel_Data { + float voltage; + float current; + float shunt; +}; + +struct INA3221_Data { + struct INA3221_Channel_Data chan[INA3221_NB_CHAN]; + uint8_t enabled_chan; + uint8_t i2caddr; +}; + +struct INA3221_Data *Ina3221Data = nullptr; +uint8_t Ina3221count = 0; +static uint8_t _ina3221_current_device = 0; + +#define D_INA3221 "INA3221" +const char INA3221_TYPE[] = D_INA3221; + +bool Ina3221SetConfig(uint8_t addr) +{ + // check if device is a INA3221 + uint16_t manufacturer_id = 0, die_id = 0; + if (!I2cValidRead16(&manufacturer_id, addr, INA3221_REG_MANUFACTURER_ID) + || (manufacturer_id != INA3221_MANUFACTURER_ID) + || !I2cValidRead16(&die_id, addr, INA3221_REG_DIE_ID) + || (die_id != INA3221_DIE_ID)) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_INA3221 ":Skipping device at addr:0x%02X is not an " D_INA3221), addr); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(D_INA3221 ":SetConfig: manId=0x%04X, dieId=0x%04X"), manufacturer_id, die_id); + return false; + } + + // write default configuration + uint16_t config = INA3221_ENABLE_MASK | + INA3221_AVERAGING_16_SAMPLES | + INA3221_VBUS_CONV_TIME_1MS | + INA3221_SHUNT_CONV_TIME_1MS | + INA3221_MODE_SHUNT_AND_BUS_CONTINOUS; + DEBUG_SENSOR_LOG(PSTR(D_INA3221 ":SetConfig: addr:0x%02X, config=0x%04X"), addr, config); + // Set Config register + if (!I2cWrite16(addr, INA3221_REG_CONFIG, config)) + return false; + + return true; +} + +bool Ina3221PowerDown(uint8_t device) +{ + uint8_t addr = Ina3221Data[device].i2caddr; + // write default configuration + uint16_t config = INA3221_MODE_POWER_DOWN; + DEBUG_SENSOR_LOG(PSTR(D_INA3221 ":PowerDown: addr:0x%02X, config=0x%04X"), addr, config); + // Set Config register + if (!I2cWrite16(addr, INA3221_REG_CONFIG, config)) + return false; + + return true; +} + +void Ina3221SetShunt(uint8_t device, uint8_t channel, float shunt) +{ + Ina3221Data[device].chan[channel].shunt = shunt; + if (shunt > 0.0) + Ina3221Data[device].enabled_chan |= (1<> 3); +} + +float Ina3221GetBusVoltage(uint8_t device, uint8_t channel) +{ + uint8_t addr = Ina3221Data[device].i2caddr; + int16_t bus_voltage = I2cReadS16(addr, INA3221_REG_BUS_VOLTAGE_CH(channel)); + DEBUG_SENSOR_LOG(D_INA3221 ":GetBusVoltage: RegVBus[%d:%d](0x%02X) = 0x%04X = %d", device, channel, INA3221_REG_BUS_VOLTAGE_CH(channel), bus_voltage, bus_voltage); + // Convert to VBus voltage in V + return INA3221C_BUS_ADC_LSB * (float)(bus_voltage >> 3); +} + +bool Ina3221Read(uint8_t device, uint8_t channel) +{ + Ina3221Data[device].chan[channel].voltage = Ina3221GetBusVoltage(device, channel); + if (Ina3221Data[device].chan[channel].shunt > 0.0) + Ina3221Data[device].chan[channel].current = Ina3221GetShuntVoltage(device, channel) / Ina3221Data[device].chan[channel].shunt; + else + Ina3221Data[device].chan[channel].current = INFINITY; + + #ifdef DEBUG_TASMOTA_SENSOR + dtostrfd(Ina3221Data[device].chan[channel].voltage,5,_ina3221_dbg1); + dtostrfd(Ina3221Data[device].chan[channel].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); + else + snprintf_P(name, sizeof(name), PSTR("%s"), INA3221_TYPE); + + 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 (0xFE & enabled_chan) { + strncat(voltage, ",", sizeof(voltage)); + strncat(current, ",", sizeof(voltage)); + strncat(power, ",", sizeof(voltage)); + } + } //if enabled + } // 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, 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