#pragma once /** * a digital multi-gas sensor for indoor air quality monitoring * https://www.sciosense.com/wp-content/uploads/documents/SC-001224-DS-7-ENS160-Datasheet.pdf */ template class ENS160 { private: I2C& i2c; static constexpr const uint8_t ADDR1 = 0x52; static constexpr const uint8_t ADDR2 = 0x53; uint8_t ADDR; static constexpr const char* NAME = "ENS160"; static constexpr const uint8_t REG_PART_ID = 0x00; static constexpr const uint8_t REG_OPMODE = 0x10; static constexpr const uint8_t REG_TEMP_IN = 0x13; static constexpr const uint8_t REG_RH_IN = 0x15; static constexpr const uint8_t REG_DEVICE_STATUS = 0x20; static constexpr const uint8_t REG_DATA_AQI = 0x21; static constexpr const uint8_t REG_DATA_TVOC = 0x22; static constexpr const uint8_t REG_DATA_ECO2 = 0x24; public: enum class Mode : uint8_t { DEEP_SLEEP = 0x00, IDLE = 0x01, STANDARD = 0x02, RESET = 0xF0, }; union Status { uint8_t raw; struct { uint8_t newgpr : 1; uint8_t newdat : 1; uint8_t valid : 2; uint8_t dummy : 2; uint8_t stater : 1; uint8_t statas : 1; } __attribute__((__packed__)); bool isNormal() const {return valid == 0;} bool isWarmUp() const {return valid == 1;} bool isStartUp() const {return valid == 2;} bool isInvalid() const {return valid == 3;} } __attribute__((__packed__)); union Result { uint8_t raw[6]; struct { Status status; uint8_t aqi; uint16_t tvoc; uint16_t eco2; } __attribute__((__packed__)); } __attribute__((__packed__)); public: ENS160(I2C& i2c, uint8_t addr = ADDR1) : i2c(i2c), ADDR(addr) { } /** always 0x01 0x60 */ uint16_t getID() { uint16_t res = 0; i2c.readReg(ADDR, 0x00, 2, (uint8_t*)&res); return res; } /** switch the mode of operation */ void setMode(Mode m) { i2c.writeReg8(ADDR, REG_OPMODE, (uint8_t)m); DELAY_MS(250); // not mentioned in the data-sheet but important? } /** set the current ambient temperature - for compensation */ void setTemp(float celsius) { float kelvin = celsius + 273.15; uint16_t tmp = (uint16_t) (kelvin * 64); i2c.writeReg(ADDR, REG_TEMP_IN, 2, (uint8_t*)&tmp); } /** set the current ambient humidity (in %) - for compensation */ void setHumi(uint8_t humi) { uint16_t tmp = humi * 512; i2c.writeReg(ADDR, REG_RH_IN, 2, (uint8_t*)&tmp); } /** status + aqi + tvoc + eco2 */ Result getAll() { Result res; memset(res.raw, 0, 6); i2c.readReg(ADDR, REG_DEVICE_STATUS, 6, res.raw); res.status = getStatus(); //res.aqi = getAQI(); //res.tvoc = getTVOC(); //res.eco2 = getECO2(); return res; } Status getStatus() { Status res; res.raw = i2c.readReg8(ADDR, REG_DEVICE_STATUS); return res; } uint8_t getAQI() { uint8_t tmp = 0; i2c.readReg(ADDR, REG_DATA_AQI, 1, &tmp); return tmp & 0b111; } uint16_t getTVOC() { uint16_t tmp = 0; i2c.readReg(ADDR, REG_DATA_TVOC, 2, (uint8_t*)&tmp); return tmp; } uint16_t getECO2() { uint16_t tmp = 0; i2c.readReg(ADDR, REG_DATA_ECO2, 2, (uint8_t*)&tmp); return tmp; } /** is the device present on the bus? */ bool isPresent() { return i2c.query(ADDR); } };