Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UnitCO2L support #31

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/arduino-esp-v2-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jobs:

unit:
- UnitCO2
- UnitCO2L
- UnitENVIII
- UnitENVIV
- UnitTVOC
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/arduino-esp-v3-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jobs:

unit:
- UnitCO2
- UnitCO2L
- UnitENVIII
- UnitENVIV
- UnitTVOC
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/arduino-m5-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jobs:

unit:
- UnitCO2
- UnitCO2L
- UnitENVIII
- UnitENVIV
- UnitTVOC
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/platformio-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ jobs:

unit:
- UnitCO2
- UnitCO2L
- UnitENVIII
- UnitENVIV
- UnitTVOC
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ CO2 is a photoacoustic Carbon Dioxide (CO2) Unit that will tell you the CO2 PPM
Library for Unit ENV using [M5UnitUnified](https://github.com/m5stack/M5UnitUnified).
M5UnitUnified is a library for unified handling of various M5 units products.

M5UnitUnified currently supports the following units SKU:U001-C, SKU:U103, SKU:U169, and SKU:U088.
### Supported units
- Unit CO2 (SKU:U103)
- Unit CO2L (SKU:U104)
- Unit ENVIII (SKU:U001-C)
- Unit ENVIV (SKU:U001-D)
- Unit ENVPro (SKU:U169)
- Unit TVOC (SKU:U088)

### SKU:U088

Expand All @@ -67,12 +73,6 @@ See also examples using conventional methods here.
#include <M5UnitUnifiedENV.h> // For UnitUnified
//#include <M5UnitENV.h> // When using M5UnitUnified, do not use it at the same time as conventional libraries
```
### Supported units
- Unit CO2
- Unit ENVIII
- Unit ENVPro
- Unit TVOC

Supported units will be added in the future.

### Required Libraries:
Expand Down
11 changes: 11 additions & 0 deletions examples/UnitUnified/UnitCO2L/PlotToSerial/PlotToSerial.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*
Example using M5UnitUnified for UnitCO2L
Required
- M5Unified: https://github.com/m5stack/M5Unified
*/
#include "main/PlotToSerial.cpp"
94 changes: 94 additions & 0 deletions examples/UnitUnified/UnitCO2L/PlotToSerial/main/PlotToSerial.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*
Example using M5UnitUnified for UnitCO2L
*/
// #define USING_M5HAL // When using M5HAL
#include <M5Unified.h>
#include <M5UnitUnified.h>
#include <M5UnitUnifiedENV.h>

namespace {
auto& lcd = M5.Display;
m5::unit::UnitUnified Units;
// m5::unit::UnitCO2 unit;
m5::unit::UnitCO2L unit;

} // namespace

using namespace m5::unit::scd4x;

void setup()
{
M5.begin();

auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda);
auto pin_num_scl = M5.getPin(m5::pin_name_t::port_a_scl);
M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl);

#if defined(USING_M5HAL)
#pragma message "Using M5HAL"
// Using M5HAL
m5::hal::bus::I2CBusConfig i2c_cfg;
i2c_cfg.pin_sda = m5::hal::gpio::getPin(pin_num_sda);
i2c_cfg.pin_scl = m5::hal::gpio::getPin(pin_num_scl);
auto i2c_bus = m5::hal::bus::i2c::getBus(i2c_cfg);
if (!Units.add(unit, i2c_bus ? i2c_bus.value() : nullptr) || !Units.begin()) {
M5_LOGE("Failed to begin");
lcd.clear(TFT_RED);
while (true) {
m5::utility::delay(10000);
}
}
#else
#pragma message "Using Wire"
// Using TwoWire
Wire.begin(pin_num_sda, pin_num_scl, 400000U);
if (!Units.add(unit, Wire) || !Units.begin()) {
M5_LOGE("Failed to begin");
lcd.clear(TFT_RED);
while (true) {
m5::utility::delay(10000);
}
}
#endif
M5_LOGI("M5UnitUnified has been begun");
M5_LOGI("%s", Units.debugInfo().c_str());

lcd.clear(TFT_DARKGREEN);
}

void loop()
{
M5.update();
auto touch = M5.Touch.getDetail();

// Periodic
Units.update();
if (unit.updated()) {
// Can be checked e.g. by serial plotters
M5_LOGI("\n>CO2:%u\n>Temperature:%2.2f\n>Humidity:%2.2f", unit.co2(), unit.temperature(), unit.humidity());
}

// Single
if (M5.BtnA.wasClicked() || touch.wasClicked()) {
static bool all{}; // false: RHT only
all = !all;
M5_LOGI("Try single shot %u, waiting measurement...", all);
unit.stopPeriodicMeasurement();
Data d{};
if (all) {
if (unit.measureSingleshot(d)) {
M5_LOGI("SingleAll: %u/%2.2f/%2.2f", d.co2(), d.temperature(), d.humidity());
}
} else {
if (unit.measureSingleshotRHT(d)) {
M5_LOGI("SingleRHT: %2.2f/%2.2f", d.temperature(), d.humidity());
}
}
unit.startPeriodicMeasurement();
}
}
8 changes: 6 additions & 2 deletions library.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
"url": "https://github.com/m5stack/M5Unit-ENV.git"
},
"dependencies": {
"M5UnitUnified": "https://github.com/m5stack/M5UnitUnified.git",
"M5UnitUnified": "https://github.com/m5stack/M5UnitUnified.git@^0.0.5",
"BME68x Sensor library": "https://github.com/boschsensortec/Bosch-BME68x-Library.git",
"bsec2": "https://github.com/boschsensortec/Bosch-BSEC2-Library"
},
"version": "1.2.0",
"version": "1.2.1",
"frameworks": [
"arduino"
],
"headers": [
"M5UnitENV.h",
"M5UnitUnifiedENV.h"
],
"platforms": "espressif32",
"license": "MIT",
"export": {
Expand Down
4 changes: 2 additions & 2 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=M5Unit-ENV
version=1.2.0
version=1.2.1
author=M5Stack
maintainer=M5Stack
sentence=Library for M5Stack UNIT ENV
Expand All @@ -8,4 +8,4 @@ category=Device Control
url=https://github.com/m5stack/M5Unit-ENV
architectures=esp32
includes=M5UnitENV.h, M5UnitUnifiedENV.h
depends=BME68x Sensor library,M5UnitUnified,M5Utility,M5HAL,bsec2
depends=M5UnitUnified (>=0.0.5),M5Utility,M5HAL,bsec2,BME68x Sensor library
4 changes: 2 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ lib_ldf_mode = deep
test_framework = googletest
test_build_src = true
lib_deps=m5stack/M5Unified
m5stack/M5UnitUnified
m5stack/M5UnitUnified@^0.0.5
https://github.com/boschsensortec/Bosch-BME68x-Library.git @ 1.2.40408

; --------------------------------
Expand Down Expand Up @@ -91,7 +91,7 @@ extends = m5base
board = m5stack-nanoc6
platform = https://github.com/platformio/platform-espressif32.git
platform_packages =
platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git
platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v5.1
platformio/framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-libs.git#idf-release/v5.1
board_build.partitions = default.csv
lib_deps = ${env.lib_deps}
Expand Down
1 change: 1 addition & 0 deletions src/M5UnitUnifiedENV.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace m5 {
namespace unit {

using UnitCO2 = m5::unit::UnitSCD40;
using UnitCO2L = m5::unit::UnitSCD41;
using UnitENVPro = m5::unit::UnitBME688;
using UnitTVOC = m5::unit::UnitSGP30;

Expand Down
21 changes: 14 additions & 7 deletions src/unit/unit_SCD40.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ void UnitSCD40::update(const bool force)
{
_updated = false;
if (inPeriodic()) {
unsigned long at{m5::utility::millis()};
auto at = m5::utility::millis();
if (force || !_latest || at >= _latest + _interval) {
Data d{};
_updated = read_measurement(d);
if (_updated) {
_latest = m5::utility::millis(); // Data acquisition takes time, so acquire again
_data->push_back(d);
_latest = at;
}
}
}
Expand Down Expand Up @@ -169,7 +169,7 @@ bool UnitSCD40::readTemperatureOffset(float& offset)
}

uint16_t u16{};
auto ret = readRegister16(GET_TEMPERATURE_OFFSET, u16, GET_TEMPERATURE_OFFSET_DURATION);
auto ret = readRegister16BE(GET_TEMPERATURE_OFFSET, u16, GET_TEMPERATURE_OFFSET_DURATION);
offset = Temperature::toFloat(u16);
return ret;
}
Expand Down Expand Up @@ -198,7 +198,7 @@ bool UnitSCD40::readSensorAltitude(uint16_t& altitude)
M5_LIB_LOGD("Periodic measurements are running");
return false;
}
return readRegister16(GET_SENSOR_ALTITUDE, altitude, GET_SENSOR_ALTITUDE_DURATION);
return readRegister16BE(GET_SENSOR_ALTITUDE, altitude, GET_SENSOR_ALTITUDE_DURATION);
}

bool UnitSCD40::writeAmbientPressure(const float pressure, const uint32_t duration)
Expand Down Expand Up @@ -278,7 +278,7 @@ bool UnitSCD40::readAutomaticSelfCalibrationEnabled(bool& enabled)
return false;
}
uint16_t u16{};
if (readRegister16(GET_AUTOMATIC_SELF_CALIBRATION_ENABLED, u16, 1)) {
if (readRegister16BE(GET_AUTOMATIC_SELF_CALIBRATION_ENABLED, u16, 1)) {
enabled = (u16 == 0x0001);
return true;
}
Expand All @@ -288,7 +288,7 @@ bool UnitSCD40::readAutomaticSelfCalibrationEnabled(bool& enabled)
bool UnitSCD40::read_data_ready_status()
{
uint16_t res{};
return readRegister16(GET_DATA_READY_STATUS, res, GET_DATA_READY_STATUS_DURATION) ? (res & 0x07FF) != 0 : false;
return readRegister16BE(GET_DATA_READY_STATUS, res, GET_DATA_READY_STATUS_DURATION) ? (res & 0x07FF) != 0 : false;
}

bool UnitSCD40::writePersistSettings(const uint32_t duration)
Expand Down Expand Up @@ -353,7 +353,7 @@ bool UnitSCD40::performSelfTest(bool& malfunction)
}

uint16_t response{};
if (readRegister16(PERFORM_SELF_TEST, response, PERFORM_SELF_TEST_DURATION)) {
if (readRegister16BE(PERFORM_SELF_TEST, response, PERFORM_SELF_TEST_DURATION)) {
malfunction = (response != 0);
return true;
}
Expand Down Expand Up @@ -397,6 +397,13 @@ bool UnitSCD40::read_measurement(Data& d, const bool all)
if (!readRegister(READ_MEASUREMENT, d.raw.data(), d.raw.size(), READ_MEASUREMENT_DURATION)) {
return false;
}

// For RHT only, previous Co2 data may be obtained and should be dismissed
if (!all) {
d.raw[0] = d.raw[1] = d.raw[2] = 0;
}

// Check CRC
m5::utility::CRC8_Checksum crc{};
for (uint_fast8_t i = all ? 0 : 1; i < 3; ++i) {
if (crc.range(d.raw.data() + i * 3, 2U) != d.raw[i * 3 + 2]) {
Expand Down
24 changes: 22 additions & 2 deletions src/unit/unit_SCD41.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ using namespace m5::unit::scd4x::command;
using namespace m5::unit::scd41;
using namespace m5::unit::scd41::command;

namespace {
// Max command duration(ms)
constexpr uint16_t MEASURE_SINGLE_SHOT_DURATION{5000};
constexpr uint16_t MEASURE_SINGLE_SHOT_RHT_ONLY_DURATION{50};
} // namespace

namespace m5 {
namespace unit {
// class UnitSCD41
Expand All @@ -26,20 +32,34 @@ const types::uid_t UnitSCD41::attr{0};

bool UnitSCD41::measureSingleshot(Data& d)
{
d = Data{};

if (inPeriodic()) {
M5_LIB_LOGD("Periodic measurements are running");
return false;
}
return writeRegister(MEASURE_SINGLE_SHOT) && read_measurement(d);

if (writeRegister(MEASURE_SINGLE_SHOT)) {
m5::utility::delay(MEASURE_SINGLE_SHOT_DURATION);
return read_measurement(d);
}
return false;
}

bool UnitSCD41::measureSingleshotRHT(Data& d)
{
d = Data{};

if (inPeriodic()) {
M5_LIB_LOGD("Periodic measurements are running");
return false;
}
return writeRegister(MEASURE_SINGLE_SHOT_RHT_ONLY) && read_measurement(d, false);

if (writeRegister(MEASURE_SINGLE_SHOT_RHT_ONLY)) {
m5::utility::delay(MEASURE_SINGLE_SHOT_RHT_ONLY_DURATION);
return read_measurement(d, false);
}
return false;
}

} // namespace unit
Expand Down
7 changes: 2 additions & 5 deletions src/unit/unit_SCD41.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ class UnitSCD41 : public UnitSCD40 {
/*!
@brief Request a single measurement
@return True if successful
@note Values are updated at 5000 ms interval
@note Blocked until measurement results are acquired (5000 ms)
@warning During periodic detection runs, an error is returned
*/
bool measureSingleshot(scd4x::Data &d);
/*!
@brief Request a single measurement temperature and humidity
@return True if successful
@note Values are updated at 50 ms interval
@note Blocked until measurement results are acquired (50 ms)
@warning Information on CO2 is invalid.
@warning During periodic detection runs, an error is returned
*/
Expand All @@ -56,10 +57,6 @@ class UnitSCD41 : public UnitSCD40 {
*/
namespace scd41 {
///@cond
// Max command duration(ms)
constexpr uint16_t MEASURE_SINGLE_SHOT_DURATION{5000};
constexpr uint16_t MEASURE_SINGLE_SHOT_RHT_ONLY_DURATION{50};

namespace command {
// Low power single shot - SCD41 only
constexpr uint16_t MEASURE_SINGLE_SHOT{0x219d};
Expand Down
Loading
Loading