Add support for AGS02MA TVOC Sensor (#24109)
* Add ags02ma library * Initial commit * fix object init * fix bugs * Update I2C Driver number Device disabled by default * refactoring for consistency
This commit is contained in:
parent
66dc5c926d
commit
96e174bcc6
@ -133,5 +133,6 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip
|
||||
92 | USE_PCF85063 | xdrv_56 | PCF85063 | 0x51 | | PCF85063 Real time clock
|
||||
93 | USE_AS33772S | xdrv_119 | AS33772S | 0x52 | Yes | AS33772S USB PD Sink Controller
|
||||
94 | USE_RV3028 | xdrv_56 | RV3028 | 0x52 | Yes | RV-3028-C7 RTC Controller
|
||||
95 | USE_AGS02MA | xsns_118 | AGS02MA | 0x1A | | TVOC Gas sensor
|
||||
|
||||
NOTE: Bus2 supported on ESP32 only.
|
||||
|
||||
28
lib/lib_i2c/AGS02MA-0.4.3/.arduino-ci.yml
Normal file
28
lib/lib_i2c/AGS02MA-0.4.3/.arduino-ci.yml
Normal file
@ -0,0 +1,28 @@
|
||||
platforms:
|
||||
rpipico:
|
||||
board: rp2040:rp2040:rpipico
|
||||
package: rp2040:rp2040
|
||||
gcc:
|
||||
features:
|
||||
defines:
|
||||
- ARDUINO_ARCH_RP2040
|
||||
warnings:
|
||||
flags:
|
||||
|
||||
packages:
|
||||
rp2040:rp2040:
|
||||
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
# - due
|
||||
# - zero
|
||||
# - leonardo
|
||||
- m4
|
||||
- esp32
|
||||
- esp8266
|
||||
# - mega2560
|
||||
- rpipico
|
||||
|
||||
386
lib/lib_i2c/AGS02MA-0.4.3/AGS02MA.cpp
Normal file
386
lib/lib_i2c/AGS02MA-0.4.3/AGS02MA.cpp
Normal file
@ -0,0 +1,386 @@
|
||||
//
|
||||
// FILE: AGS02MA.cpp
|
||||
// AUTHOR: Rob Tillaart, Viktor Balint, Beanow
|
||||
// DATE: 2021-08-12
|
||||
// VERSION: 0.4.3
|
||||
// PURPOSE: Arduino library for AGS02MA TVOC sensor
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
// REGISTERS
|
||||
#define AGS02MA_DATA 0x00
|
||||
#define AGS02MA_CALIBRATION 0x01
|
||||
#define AGS02MA_VERSION 0x11
|
||||
#define AGS02MA_SLAVE_ADDRESS 0x21
|
||||
|
||||
|
||||
|
||||
AGS02MA::AGS02MA(const uint8_t deviceAddress, TwoWire *wire)
|
||||
{
|
||||
_address = deviceAddress;
|
||||
_wire = wire;
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::begin()
|
||||
{
|
||||
_startTime = millis(); // PREHEAT TIMING
|
||||
return isConnected();
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::isConnected()
|
||||
{
|
||||
_setI2CLowSpeed();
|
||||
_wire->beginTransmission(_address);
|
||||
bool rv = ( _wire->endTransmission(true) == 0);
|
||||
_setI2CHighSpeed();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
void AGS02MA::reset()
|
||||
{
|
||||
_I2CResetSpeed = 100000;
|
||||
_startTime = millis();
|
||||
_lastRead = 0;
|
||||
_lastPPB = 0;
|
||||
_mode = 255;
|
||||
_status = AGS02MA_OK;
|
||||
_error = AGS02MA_OK;
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::setAddress(const uint8_t deviceAddress)
|
||||
{
|
||||
if ((deviceAddress < 10) or (deviceAddress > 119)) return false;
|
||||
_buffer[2] = _buffer[0] = deviceAddress;
|
||||
_buffer[3] = _buffer[1] = 0xFF ^ deviceAddress;
|
||||
_buffer[4] = _CRC8(_buffer, 4);
|
||||
if (_writeRegister(AGS02MA_SLAVE_ADDRESS))
|
||||
{
|
||||
_address = deviceAddress;
|
||||
}
|
||||
return isConnected();
|
||||
}
|
||||
|
||||
|
||||
uint8_t AGS02MA::getSensorVersion()
|
||||
{
|
||||
uint8_t version = 0xFF;
|
||||
if (_readRegister(AGS02MA_VERSION))
|
||||
{
|
||||
// for (int i = 0; i < 5; i++)
|
||||
// {
|
||||
// Serial.print(_buffer[i]);
|
||||
// Serial.print('\t');
|
||||
// }
|
||||
// Serial.println();
|
||||
// unclear what the other bytes have for information.
|
||||
// datasheet names these 3 bytes as KEEP.
|
||||
// BUFFER VALUE MEANING
|
||||
// buffer [0] == 20 year ?
|
||||
// buffer [1] == 07 month ?
|
||||
// buffer [2] == 28 day ?
|
||||
// buffer [3] == 117 VERSION
|
||||
// buffer [4] == CRC
|
||||
version = _buffer[3];
|
||||
if (_CRC8(_buffer, 5) != 0)
|
||||
{
|
||||
_error = AGS02MA_ERROR_CRC;
|
||||
}
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
uint32_t AGS02MA::getSensorDate()
|
||||
{
|
||||
uint32_t date = 0xFFFFFFFF;
|
||||
if (_readRegister(AGS02MA_VERSION))
|
||||
{
|
||||
date = 0x20;
|
||||
date <<= 8;
|
||||
date += _bin2bcd(_buffer[0]);
|
||||
date <<= 8;
|
||||
date += _bin2bcd(_buffer[1]);
|
||||
date <<= 8;
|
||||
date += _bin2bcd(_buffer[2]);
|
||||
// version = _buffer[3];
|
||||
if (_CRC8(_buffer, 5) != 0)
|
||||
{
|
||||
_error = AGS02MA_ERROR_CRC;
|
||||
}
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::setPPBMode()
|
||||
{
|
||||
_buffer[0] = 0x00;
|
||||
_buffer[1] = 0xFF;
|
||||
_buffer[2] = 0x00;
|
||||
_buffer[3] = 0xFF;
|
||||
_buffer[4] = 0x30;
|
||||
if (_writeRegister(AGS02MA_DATA))
|
||||
{
|
||||
_mode = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::setUGM3Mode()
|
||||
{
|
||||
_buffer[0] = 0x02;
|
||||
_buffer[1] = 0xFD;
|
||||
_buffer[2] = 0x02;
|
||||
_buffer[3] = 0xFD;
|
||||
_buffer[4] = 0x00;
|
||||
if (_writeRegister(AGS02MA_DATA))
|
||||
{
|
||||
_mode = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint32_t AGS02MA::readPPB()
|
||||
{
|
||||
uint32_t value = _readSensor();
|
||||
if (_error == AGS02MA_OK)
|
||||
{
|
||||
_lastRead = millis();
|
||||
_lastPPB = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _lastPPB;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
uint32_t AGS02MA::readUGM3()
|
||||
{
|
||||
uint32_t value = _readSensor();
|
||||
if (_error == AGS02MA_OK)
|
||||
{
|
||||
_lastRead = millis();
|
||||
_lastUGM3 = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _lastUGM3;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::manualZeroCalibration(uint16_t value)
|
||||
{
|
||||
_buffer[0] = 0x00;
|
||||
_buffer[1] = 0x0C;
|
||||
_buffer[2] = (uint8_t) (value >> 8);
|
||||
_buffer[3] = (uint8_t) (value & 0x00FF);
|
||||
_buffer[4] = _CRC8(_buffer, 4);
|
||||
return _writeRegister(AGS02MA_CALIBRATION);
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::getZeroCalibrationData(AGS02MA::ZeroCalibrationData &data) {
|
||||
if (!_readRegister(AGS02MA_CALIBRATION))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_CRC8(_buffer, 5) != 0)
|
||||
{
|
||||
_error = AGS02MA_ERROR_CRC;
|
||||
return false;
|
||||
}
|
||||
|
||||
_error = AGS02MA_OK;
|
||||
// Don't pollute the struct given to us, until we've handled all error cases.
|
||||
data.status = _getDataMSB();
|
||||
data.value = _getDataLSB();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int AGS02MA::lastError()
|
||||
{
|
||||
int e = _error;
|
||||
_error = AGS02MA_OK; // reset error after read
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::readRegister(uint8_t address, AGS02MA::RegisterData ®) {
|
||||
if (!_readRegister(address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_CRC8(_buffer, 5) != 0)
|
||||
{
|
||||
_error = AGS02MA_ERROR_CRC;
|
||||
return false;
|
||||
}
|
||||
|
||||
_error = AGS02MA_OK;
|
||||
// Don't pollute the struct given to us, until we've handled all error cases.
|
||||
reg.data[0] = _buffer[0];
|
||||
reg.data[1] = _buffer[1];
|
||||
reg.data[2] = _buffer[2];
|
||||
reg.data[3] = _buffer[3];
|
||||
reg.crc = _buffer[4];
|
||||
reg.crcValid = true; // checked above.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
uint32_t AGS02MA::_readSensor()
|
||||
{
|
||||
uint32_t value = 0;
|
||||
if (_readRegister(AGS02MA_DATA))
|
||||
{
|
||||
_error = AGS02MA_OK;
|
||||
_status = _buffer[0];
|
||||
if (_status & 0x01)
|
||||
{
|
||||
_error = AGS02MA_ERROR_NOT_READY;
|
||||
}
|
||||
value = _buffer[1] * 65536UL;
|
||||
value += _buffer[2] * 256;
|
||||
value += _buffer[3];
|
||||
if (_CRC8(_buffer, 5) != 0)
|
||||
{
|
||||
_error = AGS02MA_ERROR_CRC;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::_readRegister(uint8_t reg)
|
||||
{
|
||||
while (millis() - _lastRegTime < 30) yield();
|
||||
|
||||
_setI2CLowSpeed();
|
||||
|
||||
_wire->beginTransmission(_address);
|
||||
_wire->write(reg);
|
||||
_error = _wire->endTransmission(true);
|
||||
if (_error != 0)
|
||||
{
|
||||
// _error will be I2C error code
|
||||
_setI2CHighSpeed();
|
||||
return false;
|
||||
}
|
||||
// TODO investigate async interface
|
||||
delay(30);
|
||||
|
||||
if (_wire->requestFrom(_address, (uint8_t)5) != 5)
|
||||
{
|
||||
_error = AGS02MA_ERROR_READ;
|
||||
_setI2CHighSpeed();
|
||||
return false;
|
||||
}
|
||||
for (uint8_t i = 0; i < 5; i++)
|
||||
{
|
||||
_buffer[i] = _wire->read();
|
||||
}
|
||||
_error = AGS02MA_OK;
|
||||
_setI2CHighSpeed();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AGS02MA::_writeRegister(uint8_t reg)
|
||||
{
|
||||
while (millis() - _lastRegTime < 30) yield();
|
||||
_lastRegTime = millis();
|
||||
|
||||
_setI2CLowSpeed();
|
||||
|
||||
_wire->beginTransmission(_address);
|
||||
_wire->write(reg);
|
||||
for (uint8_t i = 0; i < 5; i++)
|
||||
{
|
||||
_wire->write(_buffer[i]);
|
||||
}
|
||||
_error = _wire->endTransmission(true);
|
||||
_setI2CHighSpeed();
|
||||
return (_error == 0);
|
||||
}
|
||||
|
||||
|
||||
void AGS02MA::_setI2CLowSpeed()
|
||||
{
|
||||
#if defined (__AVR__)
|
||||
// TWBR = 255; // == 30.4 KHz with TWSR = 0x00
|
||||
TWBR = 78; // == 25.0 KHZ
|
||||
TWSR = 0x01; // pre-scaler = 4
|
||||
#else
|
||||
_wire->setClock(AGS02MA_I2C_CLOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AGS02MA::_setI2CHighSpeed()
|
||||
{
|
||||
#if defined (__AVR__)
|
||||
TWSR = 0x00;
|
||||
#endif
|
||||
_wire->setClock(_I2CResetSpeed);
|
||||
}
|
||||
|
||||
|
||||
uint16_t AGS02MA::_getDataMSB()
|
||||
{
|
||||
return (_buffer[0] << 8) + _buffer[1];
|
||||
}
|
||||
|
||||
|
||||
uint16_t AGS02MA::_getDataLSB()
|
||||
{
|
||||
return (_buffer[2] << 8) + _buffer[3];
|
||||
}
|
||||
|
||||
|
||||
uint8_t AGS02MA::_CRC8(uint8_t * buf, uint8_t size)
|
||||
{
|
||||
uint8_t crc = 0xFF; // start value
|
||||
for (uint8_t b = 0; b < size; b++)
|
||||
{
|
||||
crc ^= buf[b];
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 0x80) crc = (crc << 1) ^ 0x31;
|
||||
else crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
uint8_t AGS02MA::_bin2bcd (uint8_t value)
|
||||
{
|
||||
return value + 6 * (value / 10);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
145
lib/lib_i2c/AGS02MA-0.4.3/AGS02MA.h
Normal file
145
lib/lib_i2c/AGS02MA-0.4.3/AGS02MA.h
Normal file
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
//
|
||||
// FILE: AGS02MA.h
|
||||
// AUTHOR: Rob Tillaart, Viktor Balint, Beanow
|
||||
// DATE: 2021-08-12
|
||||
// VERSION: 0.4.3
|
||||
// PURPOSE: Arduino library for AGS02MA TVOC sensor
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
|
||||
#define AGS02MA_LIB_VERSION (F("0.4.3"))
|
||||
|
||||
#define AGS02MA_OK 0
|
||||
#define AGS02MA_ERROR -10
|
||||
#define AGS02MA_ERROR_CRC -11
|
||||
#define AGS02MA_ERROR_READ -12
|
||||
#define AGS02MA_ERROR_NOT_READY -13
|
||||
#define AGS02MA_ERROR_REQUEST -14
|
||||
|
||||
|
||||
#define AGS02MA_I2C_CLOCK 25000 // max 30000
|
||||
|
||||
|
||||
class AGS02MA
|
||||
{
|
||||
public:
|
||||
struct RegisterData
|
||||
{
|
||||
uint8_t data[4];
|
||||
uint8_t crc;
|
||||
bool crcValid;
|
||||
};
|
||||
|
||||
struct ZeroCalibrationData
|
||||
{
|
||||
/**
|
||||
* Warning, the exact meaning of this status is not fully documented.
|
||||
* It seems like it's a bit mask:
|
||||
* 0000 1100 | 0x0C | 12 | Typical value
|
||||
* 0000 1101 | 0x0D | 13 | Sometimes seen on v117
|
||||
* 0111 1101 | 0x7D | 125 | Seen on v118, after power-off (gives different data than 12!)
|
||||
*/
|
||||
uint16_t status;
|
||||
uint16_t value;
|
||||
};
|
||||
|
||||
// address 26 = 0x1A
|
||||
explicit AGS02MA(const uint8_t deviceAddress = 26, TwoWire *wire = &Wire);
|
||||
|
||||
bool begin();
|
||||
bool isConnected();
|
||||
void reset();
|
||||
|
||||
bool isHeated() { return (millis() - _startTime) > 120000UL; };
|
||||
|
||||
|
||||
// CONFIGURATION
|
||||
bool setAddress(const uint8_t deviceAddress);
|
||||
uint8_t getAddress() { return _address; };
|
||||
uint8_t getSensorVersion();
|
||||
uint32_t getSensorDate();
|
||||
|
||||
// to set the speed the I2C bus should return to
|
||||
// as the device operates at very low bus speed of 30 kHz.
|
||||
void setI2CResetSpeed(uint32_t speed) { _I2CResetSpeed = speed; };
|
||||
uint32_t getI2CResetSpeed() { return _I2CResetSpeed; };
|
||||
|
||||
// to be called after at least 5 minutes in fresh air.
|
||||
bool zeroCalibration() { return manualZeroCalibration(0); };
|
||||
|
||||
/**
|
||||
* Set the zero calibration value manually.
|
||||
* To be called after at least 5 minutes in fresh air.
|
||||
* For v117: 0-65535 = automatic calibration.
|
||||
* For v118: 0 = automatic calibration, 1-65535 manual calibration.
|
||||
*/
|
||||
bool manualZeroCalibration(uint16_t value = 0);
|
||||
bool getZeroCalibrationData(ZeroCalibrationData &data);
|
||||
|
||||
|
||||
// MODE
|
||||
bool setPPBMode();
|
||||
bool setUGM3Mode();
|
||||
uint8_t getMode() { return _mode; };
|
||||
|
||||
|
||||
// READ functions
|
||||
uint32_t readPPB(); // parts per billion 10^9
|
||||
uint32_t readUGM3(); // microgram per cubic meter
|
||||
|
||||
// derived read functions
|
||||
float readPPM() { return readPPB() * 0.001; }; // parts per million
|
||||
float readMGM3() { return readUGM3() * 0.001; }; // milligram per cubic meter
|
||||
float readUGF3() { return readUGM3() * 0.0283168466; }; // microgram per cubic feet
|
||||
|
||||
float lastPPM() { return _lastPPB * 0.001; };
|
||||
uint32_t lastPPB() { return _lastPPB; }; // fetch last PPB measurement
|
||||
uint32_t lastUGM3() { return _lastUGM3; }; // fetch last UGM3 measurement
|
||||
|
||||
|
||||
// STATUS
|
||||
uint32_t lastRead() { return _lastRead; }; // timestamp last measurement
|
||||
int lastError();
|
||||
uint8_t lastStatus() { return _status; };
|
||||
uint8_t dataReady() { return _status & 0x01; };
|
||||
|
||||
// Reading registers
|
||||
bool readRegister(uint8_t address, RegisterData ®);
|
||||
|
||||
|
||||
private:
|
||||
uint32_t _readSensor();
|
||||
bool _readRegister(uint8_t reg);
|
||||
bool _writeRegister(uint8_t reg);
|
||||
|
||||
uint32_t _I2CResetSpeed = 100000;
|
||||
uint32_t _startTime = 0;
|
||||
uint32_t _lastRead = 0;
|
||||
uint32_t _lastRegTime = 0;
|
||||
uint32_t _lastPPB = 0;
|
||||
uint32_t _lastUGM3 = 0;
|
||||
uint8_t _address = 0;
|
||||
uint8_t _mode = 255;
|
||||
uint8_t _status = 0;
|
||||
uint8_t _buffer[5];
|
||||
|
||||
void _setI2CLowSpeed();
|
||||
void _setI2CHighSpeed();
|
||||
uint16_t _getDataMSB();
|
||||
uint16_t _getDataLSB();
|
||||
uint8_t _CRC8(uint8_t * buf, uint8_t size);
|
||||
uint8_t _bin2bcd(uint8_t val);
|
||||
|
||||
int _error = AGS02MA_OK;
|
||||
|
||||
TwoWire* _wire;
|
||||
};
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
65
lib/lib_i2c/AGS02MA-0.4.3/CHANGELOG.md
Normal file
65
lib/lib_i2c/AGS02MA-0.4.3/CHANGELOG.md
Normal file
@ -0,0 +1,65 @@
|
||||
# Change Log AGS02MA
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
|
||||
## [0.4.3] - 2025-08-15
|
||||
- update readme.md
|
||||
- update license
|
||||
- minor edits
|
||||
|
||||
## [0.4.2] - 2024-02-03
|
||||
- update readme.md
|
||||
- added multiplexer section
|
||||
- extended PPB "health" table
|
||||
- clean up examples
|
||||
- refactor conditional code
|
||||
- added **setI2CLowSpeed()** and **setI2CHighSpeed()**
|
||||
- improved error handling a bit.
|
||||
- added **AGS02MA_ERROR_REQUEST**
|
||||
- redo **readRegister()**
|
||||
- minor edits
|
||||
|
||||
## [0.4.1] - 2023-12-10
|
||||
- fix #26, error in readme.
|
||||
|
||||
## [0.4.0] - 2023-12-06
|
||||
- refactor API, begin()
|
||||
- update readme.md
|
||||
|
||||
----
|
||||
|
||||
## [0.3.4] - 2023-09-25
|
||||
- add Wire1 support for ESP32
|
||||
- update readme.md
|
||||
- minor edits
|
||||
|
||||
## [0.3.3] - 2023-01-21
|
||||
- update GitHub actions
|
||||
- update license 2023
|
||||
- update keywords
|
||||
- minor edit readme.md
|
||||
- minor edit code
|
||||
- add CHANGELOG.md (for real)
|
||||
|
||||
## [0.3.2] - 2022-10-26
|
||||
- add CHANGELOG.md
|
||||
- add RP2040 in build
|
||||
|
||||
----
|
||||
|
||||
## no info
|
||||
|
||||
- 0.3.1
|
||||
- 0.3.0
|
||||
- 0.2.0
|
||||
- 0.1.4
|
||||
- 0.1.3
|
||||
- 0.1.2
|
||||
- 0.1.1
|
||||
- 0.1.0
|
||||
|
||||
21
lib/lib_i2c/AGS02MA-0.4.3/LICENSE
Normal file
21
lib/lib_i2c/AGS02MA-0.4.3/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2025 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
400
lib/lib_i2c/AGS02MA-0.4.3/README.md
Normal file
400
lib/lib_i2c/AGS02MA-0.4.3/README.md
Normal file
@ -0,0 +1,400 @@
|
||||
|
||||
[](https://github.com/marketplace/actions/arduino_ci)
|
||||
[](https://github.com/RobTillaart/AGS02MA/actions/workflows/arduino-lint.yml)
|
||||
[](https://github.com/RobTillaart/AGS02MA/actions/workflows/jsoncheck.yml)
|
||||
[](https://github.com/RobTillaart/AGS02MA/issues)
|
||||
|
||||
[](https://github.com/RobTillaart/AGS02MA/blob/master/LICENSE)
|
||||
[](https://github.com/RobTillaart/AGS02MA/releases)
|
||||
[](https://registry.platformio.org/libraries/robtillaart/AGS02MA)
|
||||
|
||||
|
||||
# AGS02MA
|
||||
|
||||
Arduino library for AGS02MA TVOC sensor.
|
||||
|
||||
|
||||
### Description
|
||||
|
||||
**Experimental**
|
||||
|
||||
This library is experimental, so please use with care.
|
||||
|
||||
The AGS02MA is a sensor that measures the TVOC = Total Volatile Organic Compounds
|
||||
in the air. It does not measure a specific gas, but several.
|
||||
|
||||
|
||||
Note the warning about the I2C low speed, the device works at max 30 KHz.
|
||||
Since 0.3.1 this library uses 25 KHz.
|
||||
|
||||
Feedback as always, is welcome. Please open an issue.
|
||||
|
||||
Note this library is **not** meant to replace professional monitoring systems.
|
||||
|
||||
|
||||
### 0.4.0 Breaking change
|
||||
|
||||
Version 0.4.0 introduced a breaking change.
|
||||
You cannot set the pins in **begin()** any more.
|
||||
This reduces the dependency of processor dependent Wire implementations.
|
||||
The user has to call **Wire.begin()** and can optionally set the Wire pins
|
||||
before calling **begin()**.
|
||||
|
||||
|
||||
### Related
|
||||
|
||||
- https://github.com/RobTillaart/AGS02MA TVOC sensor
|
||||
- https://github.com/RobTillaart/AGS2616 H2 sensor
|
||||
- https://github.com/RobTillaart/AGS3870 CH4 sensor
|
||||
- https://github.com/RobTillaart/AGS3871 CO sensor
|
||||
- https://www.renesas.com/us/en/document/whp/overview-tvoc-and-indoor-air-quality
|
||||
- https://github.com/RobTillaart/SGP30 (experimental)
|
||||
- https://github.com/RobTillaart/AtomicWeight (determine Mass from chemical formula)
|
||||
- https://github.com/RobTillaart/map2colour
|
||||
|
||||
|
||||
## I2C
|
||||
|
||||
### Pin layout from left to right
|
||||
|
||||
Always check datasheet!
|
||||
|
||||
| Front L->R | Description |
|
||||
|:------------:|:--------------|
|
||||
| pin 1 | VDD +5V |
|
||||
| pin 2 | SDA data |
|
||||
| pin 3 | GND |
|
||||
| pin 4 | SCL clock |
|
||||
|
||||
|
||||
### Address
|
||||
|
||||
The device has a fixed address of 26 or 0x1A.
|
||||
|
||||
The device works at 100 kHz I2C bus speed (datasheet).
|
||||
|
||||
Note: several AGS devices use the same I2C address 0x1A.
|
||||
Known are the AGS2616 (H2), AGS3870 (CH4), AGS3871 (CO), AGS02MA (TVOC).
|
||||
If you want to use them on one I2C bus, you need multiplexing.
|
||||
See section below.
|
||||
|
||||
|
||||
### WARNING - LOW SPEED
|
||||
|
||||
The sensor uses I2C at very low speed <= 30 KHz.
|
||||
For an Arduino UNO the lowest speed supported is about 30.4KHz (TWBR = 255) which works
|
||||
in my testruns so far.
|
||||
First runs with Arduino UNO indicate 2 failed reads in > 500 Reads, so less than 1%
|
||||
failure rate.
|
||||
|
||||
Tests with ESP32 / ESP8266 at 30 KHz look good,
|
||||
tests with ESP32 at lower clock speeds are to be done but expected to work.
|
||||
|
||||
The library sets the clock speed to 30 KHz (for non AVR) during operation
|
||||
and resets the I2C clock speed default to 100 KHz after operation.
|
||||
This is done to minimize interference with the communication of other devices.
|
||||
The "reset clock speed" can be changed with **setI2CResetSpeed(speed)** e.g. to 200 or 400 KHz.
|
||||
|
||||
|
||||
### 0.3.1 fix.
|
||||
|
||||
Version 0.3.1 sets the **I2C prescaler TWSR** register of the Arduino UNO to 4 so the lowest
|
||||
speed possible is reduced to about 8 KHz.
|
||||
A test run 4 hours with 6000++ reads on an UNO at 25 KHz gave 0 errors.
|
||||
So the communication speed will be set to 25 KHz, also for other boards, for stability.
|
||||
After communication the I2C clock (+ prescaler) is reset again as before.
|
||||
|
||||
|
||||
### I2C multiplexing
|
||||
|
||||
Sometimes you need to control more devices than possible with the default
|
||||
address range the device provides.
|
||||
This is possible with an I2C multiplexer e.g. TCA9548 which creates up
|
||||
to eight channels (think of it as I2C subnets) which can use the complete
|
||||
address range of the device.
|
||||
|
||||
Drawback of using a multiplexer is that it takes more administration in
|
||||
your code e.g. which device is on which channel.
|
||||
This will slow down the access, which must be taken into account when
|
||||
deciding which devices are on which channel.
|
||||
Also note that switching between channels will slow down other devices
|
||||
too if they are behind the multiplexer.
|
||||
|
||||
- https://github.com/RobTillaart/TCA9548
|
||||
|
||||
|
||||
## Version 118 problems
|
||||
|
||||
The library can request the version with **getSensorVersion()**.
|
||||
My devices all report version 117 and this version is used to develop / test this library.
|
||||
There are devices reported with version 118 which behave differently.
|
||||
|
||||
|
||||
### ugM3 not supported
|
||||
|
||||
See - https://github.com/RobTillaart/AGS02MA/issues/11
|
||||
|
||||
The version 118 seems only to support the **PPB** and not the **ugM3** mode.
|
||||
It is unclear if this is an incident, bug or a structural change in the firmware.
|
||||
|
||||
If you encounter similar problems with setting the mode (any version), please let me know.
|
||||
That will help indicating if this is a "structural change" or incident.
|
||||
|
||||
|
||||
### Calibrate problem!
|
||||
|
||||
See - https://github.com/RobTillaart/AGS02MA/issues/13
|
||||
|
||||
In this issue a problem is reported with a version 118 sensor.
|
||||
The problem exposed itself after running the calibration sketch (command).
|
||||
The problem has been confirmed by a 2nd version 118 sensor.
|
||||
Additional calibration runs did not fix the problem.
|
||||
Version 117 seem to have no problems with calibration.
|
||||
|
||||
**Advice**: do **NOT** calibrate a version 118.
|
||||
|
||||
Note: the version 0.2.0 determines the version in the calibration function so
|
||||
it won't calibrate any non 117 version.
|
||||
|
||||
|
||||
### Please report your experiences.
|
||||
|
||||
If you have a AGS20MA device, version 117 or 118 or other,
|
||||
please let me know your experiences
|
||||
with the sensor and this (or other) library.
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
```cpp
|
||||
#include "AGS02MA.h"
|
||||
```
|
||||
|
||||
### Constructor
|
||||
|
||||
- **AGS02MA(uint8_t deviceAddress = 26, TwoWire \*wire = &Wire)** constructor,
|
||||
with default address and default I2C interface.
|
||||
- **bool begin()** initialize the library.
|
||||
Returns false if deviceAddress cannot be seen on the I2C bus.
|
||||
- **bool isConnected()** returns true if deviceAddress can be seen on I2C, false otherwise.
|
||||
- **void reset()** resets the internal variables.
|
||||
|
||||
|
||||
### Heating
|
||||
|
||||
- **bool isHeated()** returns true if 2 minutes have passed after call of **begin()**.
|
||||
Otherwise the device is not optimal ready.
|
||||
According to the datasheet, preheating will improve the quality of the measurements.
|
||||
Note: if begin() is not called, isHeated() might be incorrect.
|
||||
- **uint32_t lastRead()** returns the last time the device is read,
|
||||
timestamp is in milliseconds since start.
|
||||
Returns 0 if **readPPB()** or **readUGM3()** is not called yet.
|
||||
This function allows to implement sort of asynchronous wait.
|
||||
One must keep reads / measurements at least 1.5 seconds but preferred 3 seconds
|
||||
apart according to the datasheet.
|
||||
|
||||
|
||||
### Administration
|
||||
|
||||
- **bool setAddress(const uint8_t deviceAddress)** sets a new address for the sensor.
|
||||
If function succeeds the address changes immediately and will be persistent over a reboot.
|
||||
- **uint8_t getAddress()** returns the set address. Default the function will return 26 or 0x1A.
|
||||
- **uint8_t getSensorVersion()** reads sensor version from the device.
|
||||
If the version cannot be read the function will return 255.
|
||||
My test sensors all return version 117, version 118 is reported to exist too.
|
||||
- **uint32_t getSensorDate()** (experimental) reads bytes from the sensor that seem
|
||||
to indicate the production date(?).
|
||||
This date is encoded in an uint32_t to minimize footprint as it is a debug function.
|
||||
|
||||
```cpp
|
||||
uint32_t dd = sensor.getSensorDate();
|
||||
Serial.println(dd, HEX); // prints YYYYMMDD e.g. 20210203
|
||||
```
|
||||
|
||||
|
||||
### I2C clock speed
|
||||
|
||||
The library sets the clock speed to 25 KHz during operation
|
||||
and resets it to 100 KHz after operation.
|
||||
This is done to minimize interference with the communication of other devices.
|
||||
The following function can change the I2C reset speed to e.g. 200 or 400 KHz.
|
||||
|
||||
- **void setI2CResetSpeed(uint32_t speed)** sets the I2C speed the library need to reset the I2C speed to.
|
||||
- **uint32_t getI2CResetSpeed()** returns the value set. Default is 100 KHz.
|
||||
|
||||
|
||||
### setMode
|
||||
|
||||
The default mode at startup of the sensor is PPB = parts per billion.
|
||||
|
||||
- **bool setPPBMode()** sets device in PartPerBillion mode. Returns true on success.
|
||||
- **bool setUGM3Mode()** sets device in micro gram per cubic meter mode. Returns true on success.
|
||||
- **uint8_t getMode()** returns mode set. 0 = PPB, 1 = UGm3, 255 = not set.
|
||||
|
||||
|
||||
### Air quality classification
|
||||
|
||||
Indicative description and colour representation.
|
||||
|
||||
| TVOC(ppb) | Scale | Description | Colour | Notes |
|
||||
|:---------:|:-------:|:---------------------:|:-------------|:--------|
|
||||
| <= 220 | 1 | Good | Green |
|
||||
| <= 660 | 3 | Moderate | Yellow |
|
||||
| <= 1430 | 7 | Bad | Orange |
|
||||
| <= 2200 | 10 | Unhealthy | Red |
|
||||
| <= 3300 | 15 | Very unhealthy | Purple | add pulsating effect
|
||||
| <= 5500 | 25 | Hazardous | Deep Purple | add pulsating effect
|
||||
| > 5500 | 50 | Extremely Hazardous | Deep Purple | add pulsating effect
|
||||
|
||||
[Source](https://learn.kaiterra.com/en/resources/understanding-tvoc-volatile-organic-compounds)
|
||||
|
||||
- Scale is a relative (linear) scale where 220 ~~ 1
|
||||
- Colour is an indicative colour mapping.
|
||||
- https://github.com/RobTillaart/map2colour for continuous colour scale mapping.
|
||||
|
||||
|
||||
### PPB versus UGM3
|
||||
|
||||
There is no 1 to 1 relation between the PPB and the uG/m3 readings as this relation depends
|
||||
on the weight of the individual molecules.
|
||||
PPB is therefore an more an absolute indicator where uG/m3 is sort of relative indicator.
|
||||
If the gas is unknown, PPB is in my opinion the preferred measurement.
|
||||
|
||||
|
||||
From an unverified source the following formula:
|
||||
M = molecular weight of the gas.
|
||||
|
||||
**μg/m3 = ppb \* M \* 12.187 / (273.15 + °C)**
|
||||
|
||||
Simplified formula for 1 atm @ 25°C:
|
||||
|
||||
**μg/m3 = ppb \* M \* 0.04087539829**
|
||||
|
||||
Some known gasses
|
||||
|
||||
| gas | Common name | ratio ppb-μg/m3 | molecular weight M |
|
||||
|:-------|:--------------------|:----------------------|:--------------------:|
|
||||
| SO2 | Sulphur dioxide | 1 ppb = 2.62 μg/m3 | 64 gr/mol |
|
||||
| NO2 | Nitrogen dioxide | 1 ppb = 1.88 μg/m3 | 46 gr/mol |
|
||||
| NO | Nitrogen monoxide | 1 ppb = 1.25 μg/m3 | 30 gr/mol |
|
||||
| O3 | Ozone | 1 ppb = 2.00 μg/m3 | 48 gr/mol |
|
||||
| CO | Carbon Monoxide | 1 ppb = 1.145 μg/m3 | 28 gr/mol |
|
||||
| C6H6 | Benzene | 1 ppb = 3.19 μg/m3 | 78 gr/mol |
|
||||
|
||||
|
||||
- https://github.com/RobTillaart/AtomicWeight (determine Mass from chemical formula)
|
||||
|
||||
|
||||
### Read the sensor
|
||||
|
||||
WARNING: The datasheet advises to take 3 seconds between reads.
|
||||
Tests gave stable results at 1.5 second intervals.
|
||||
Use this faster rate at your own risk.
|
||||
|
||||
- **uint32_t readPPB()** reads the PPB (parts per billion) from the device.
|
||||
Typical value should be between 1 .. 999999.
|
||||
Returns **lastPPB()** value if failed so one does not get sudden jumps in graphs.
|
||||
Check **lastStatus()** and **lastError()** to get more info about the success of the read().
|
||||
Time needed is ~35 milliseconds (which might cause problems).
|
||||
- **uint32_t readUGM3()** reads UGM3 (microgram per cubic meter) current value from device.
|
||||
Typical values depend on the molecular weight of the TVOC.
|
||||
Returns **lastUGM3()** if failed so one does not get sudden jumps in graphs.
|
||||
|
||||
Wrappers
|
||||
|
||||
- **float readPPM()** returns parts per million (PPM).
|
||||
This function is a wrapper around readPPB().
|
||||
Typical value should be between 0.01 .. 999.99
|
||||
- **float readMGM3()** returns milligram per cubic meter.
|
||||
- **float readUGF3()** returns microgram per cubic feet.
|
||||
|
||||
|
||||
### Error Codes
|
||||
|
||||
| ERROR_CODES | value |
|
||||
|:----------------------------|:-------:|
|
||||
| AGS02MA_OK | 0 |
|
||||
| AGS02MA_ERROR | -10 |
|
||||
| AGS02MA_ERROR_CRC | -11 |
|
||||
| AGS02MA_ERROR_READ | -12 |
|
||||
| AGS02MA_ERROR_NOT_READY | -13 |
|
||||
|
||||
|
||||
### Cached values
|
||||
|
||||
- **float lastPPM()** returns last readPPM (parts per million) value (cached).
|
||||
- **uint32_t lastPPB()** returns last read PPB (parts per billion) value (cached). Should be between 1..999999.
|
||||
- **uint32_t lastUGM3()** returns last read UGM3 (microgram per cubic meter) value (cached).
|
||||
|
||||
|
||||
### Calibration
|
||||
|
||||
- **bool zeroCalibration()** to be called after at least 5 minutes in fresh air.
|
||||
See example sketch.
|
||||
- **bool manualZeroCalibration(uint16_t value = 0)** Set the zero calibration value manually.
|
||||
To be called after at least 5 minutes in fresh air.
|
||||
- For v117: 0-65535 = automatic calibration.
|
||||
- For v118: 0 = automatic calibration, 1-65535 manual calibration.
|
||||
- **bool getZeroCalibrationData(ZeroCalibrationData &data)** fills a data struct with the
|
||||
current zero calibration status and value.
|
||||
Returns true on success.
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
- **bool readRegister(uint8_t address, RegisterData ®)** fills a data struct with the chip's register data at that address.
|
||||
Primarily intended for troubleshooting and analysis of the sensor. Not recommended to build applications on top of this method's raw data.
|
||||
Returns true when the **RegisterData** is filled, false when the data could not be read.
|
||||
Note: unlike other public methods, CRC errors don't return false or show up in `lastError()`,
|
||||
instead the CRC result is stored in `RegisterData.crcValid`.
|
||||
- **int lastError()** returns last error.
|
||||
- **uint8_t lastStatus()** returns status byte from last read.
|
||||
Read datasheet or table below for details. A new read is needed to update this.
|
||||
- **uint8_t dataReady()** returns RDY bit from last read.
|
||||
|
||||
|
||||
### Status bits.
|
||||
|
||||
| bit | description | notes |
|
||||
|:-----:|:------------------------------------|:--------|
|
||||
| 7-4 | internal use |
|
||||
| 3-1 | 000 = PPB 001 = uG/M3 |
|
||||
| 0 | RDY bit 0 = ready 1 = not ready | 1 == busy
|
||||
|
||||
|
||||
## Future
|
||||
|
||||
#### Must
|
||||
|
||||
- improve documentation
|
||||
- references?
|
||||
|
||||
#### Should
|
||||
|
||||
- check the mode bits of the status byte with internal \_mode.
|
||||
- maximize robustness of state
|
||||
- test with hardware
|
||||
- different gasses ? indoor / outdoor?
|
||||
- test with different processors
|
||||
- isHeated() bugs if begin() is not called before...
|
||||
|
||||
#### Could
|
||||
|
||||
- elaborate error handling.
|
||||
- create an async interface for **readPPB()** if possible
|
||||
- delay(30) blocks performance ==> async version of **readRegister()**
|
||||
- could introduce complex I2C speed handling...
|
||||
- separate state - request pending or so?
|
||||
- move code to .cpp?
|
||||
|
||||
#### Wont
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
If you appreciate my libraries, you can support the development and maintenance.
|
||||
Improve the quality of the libraries by providing issues and Pull Requests, or
|
||||
donate through PayPal or GitHub sponsors.
|
||||
|
||||
Thank you,
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
//
|
||||
// FILE: AGS02MA_PPB.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
Serial.print("VERSION:\t");
|
||||
Serial.println(AGS.getSensorVersion());
|
||||
|
||||
// pre-heating improves measurement quality
|
||||
// can be skipped
|
||||
Serial.println("\nWarming up (120 seconds = 24 dots)");
|
||||
while (AGS.isHeated() == false)
|
||||
{
|
||||
delay(5000);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
b = AGS.setPPBMode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
|
||||
uint8_t version = AGS.getSensorVersion();
|
||||
Serial.print("VERS:\t");
|
||||
Serial.println(version);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(3000);
|
||||
uint32_t value = AGS.readPPB();
|
||||
Serial.print("PPB:\t");
|
||||
Serial.print(value);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,75 @@
|
||||
//
|
||||
// FILE: AGS02MA_PPB_TIMING.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
//
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
Serial.print("VERS:\t");
|
||||
Serial.println(AGS.getSensorVersion());
|
||||
|
||||
// pre-heating improves measurement quality
|
||||
// can be skipped
|
||||
Serial.println("\nWarming up (120 seconds = 24 dots)");
|
||||
while (AGS.isHeated() == false)
|
||||
{
|
||||
delay(5000);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
b = AGS.setPPBMode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(1500);
|
||||
uint32_t start = millis();
|
||||
uint32_t value = AGS.readPPB();
|
||||
uint32_t stop = millis();
|
||||
|
||||
uint32_t duration = stop - start;
|
||||
Serial.print(duration);
|
||||
Serial.print("\t");
|
||||
Serial.print(value);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
|
||||
30 KHz
|
||||
|
||||
16:14:33.046 -> ...\AGS02MA_PPB_TIMING.ino
|
||||
16:14:33.046 -> AGS02MA_LIB_VERSION: 0.3.0
|
||||
16:14:33.046 ->
|
||||
16:14:33.046 -> BEGIN: 1
|
||||
16:14:33.046 -> VERS: 117
|
||||
16:14:33.093 ->
|
||||
16:14:33.093 -> Warming up (120 seconds = 24 dots)
|
||||
16:14:38.107 -> ........................
|
||||
16:16:33.243 -> MODE: 1 0
|
||||
16:16:34.790 -> 32 549 10 0
|
||||
16:16:36.325 -> 32 547 10 0
|
||||
16:16:37.872 -> 31 545 10 0
|
||||
16:16:39.418 -> 32 545 10 0
|
||||
16:16:40.922 -> 33 544 10 0
|
||||
16:16:42.469 -> 33 543 10 0
|
||||
16:16:44.015 -> 33 542 10 0
|
||||
16:16:45.562 -> 33 543 10 0
|
||||
16:16:47.062 -> 33 536 10 0
|
||||
16:16:48.608 -> 33 541 10 0
|
||||
16:16:50.155 -> 33 537 10 0
|
||||
16:16:51.701 -> 32 537 10 0
|
||||
16:16:53.201 -> 33 536 10 0
|
||||
16:16:54.747 -> 33 535 10 0
|
||||
16:16:56.294 -> 33 534 10 0
|
||||
16:16:57.810 -> 32 533 10 0
|
||||
16:16:59.357 -> 32 531 10 0
|
||||
@ -0,0 +1,27 @@
|
||||
|
||||
10 KHz (TWBR 198, TWSR 1) just a test
|
||||
|
||||
16:08:08.836 -> ...\AGS02MA_PPB_TIMING.ino
|
||||
16:20:01.824 -> AGS02MA_LIB_VERSION: 0.3.1
|
||||
16:20:01.824 ->
|
||||
16:20:01.824 -> BEGIN: 1
|
||||
16:20:01.824 -> VERS: 117
|
||||
16:20:01.871 ->
|
||||
16:20:01.871 -> Warming up (120 seconds = 24 dots)
|
||||
16:20:06.885 -> ........................
|
||||
16:22:02.077 -> MODE: 1 0
|
||||
16:22:03.624 -> 38 476 10 0
|
||||
16:22:05.165 -> 38 474 10 0
|
||||
16:22:06.712 -> 38 471 10 0
|
||||
16:22:08.247 -> 38 474 10 0
|
||||
16:22:09.794 -> 38 471 10 0
|
||||
16:22:11.325 -> 38 472 10 0
|
||||
16:22:12.871 -> 38 468 10 0
|
||||
16:22:14.418 -> 37 465 10 0
|
||||
16:22:15.917 -> 38 463 10 0
|
||||
16:22:17.464 -> 38 463 10 0
|
||||
16:22:19.016 -> 38 459 10 0
|
||||
16:22:20.547 -> 37 460 10 0
|
||||
16:22:22.094 -> 36 459 10 0
|
||||
16:22:23.640 -> 38 461 10 0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
25 KHz
|
||||
|
||||
16:08:08.836 -> ...\AGS02MA_PPB_TIMING.ino
|
||||
16:08:08.836 -> AGS02MA_LIB_VERSION: 0.3.1
|
||||
16:08:08.836 ->
|
||||
16:08:08.836 -> BEGIN: 1
|
||||
16:08:08.836 -> VERS: 117
|
||||
16:08:08.929 ->
|
||||
16:08:08.929 -> Warming up (120 seconds = 24 dots)
|
||||
16:08:13.944 -> ........................
|
||||
16:10:09.086 -> MODE: 1 0
|
||||
16:10:10.633 -> 33 845 10 0
|
||||
16:10:12.179 -> 32 846 10 0
|
||||
16:10:13.726 -> 32 847 10 0
|
||||
16:10:15.225 -> 33 847 10 0
|
||||
16:10:16.772 -> 32 847 10 0
|
||||
16:10:18.318 -> 33 841 10 0
|
||||
16:10:19.849 -> 33 835 10 0
|
||||
16:10:21.396 -> 34 829 10 0
|
||||
16:10:22.895 -> 33 825 10 0
|
||||
16:10:24.442 -> 33 828 10 0
|
||||
16:10:25.988 -> 33 823 10 0
|
||||
16:10:27.535 -> 34 824 10 0
|
||||
16:10:29.081 -> 33 821 10 0
|
||||
16:10:30.581 -> 33 821 10 0
|
||||
16:10:32.127 -> 33 816 10 0
|
||||
16:10:33.674 -> 34 826 10 0
|
||||
16:10:35.221 -> 33 839 10 0
|
||||
16:10:36.720 -> 33 855 10 0
|
||||
16:10:38.267 -> 33 857 10 0
|
||||
16:10:39.813 -> 33 857 10 0
|
||||
@ -0,0 +1,71 @@
|
||||
//
|
||||
// FILE: AGS02MA_PPM.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
//
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
Serial.print("VERSION:\t");
|
||||
Serial.println(AGS.getSensorVersion());
|
||||
|
||||
// pre-heating improves measurement quality
|
||||
// can be skipped
|
||||
Serial.println("\nWarming up (120 seconds = 24 dots)");
|
||||
while (AGS.isHeated() == false)
|
||||
{
|
||||
delay(5000);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
b = AGS.setPPBMode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(3000);
|
||||
Serial.print("PPM:\t");
|
||||
Serial.print(AGS.readPPM(), 3);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.dataReady(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
//
|
||||
// FILE: AGS02MA_UGM3.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
// pre-heating improves measurement quality
|
||||
// can be skipped
|
||||
Serial.println("\nWarming up (120 seconds = 24 dots)");
|
||||
while (AGS.isHeated() == false)
|
||||
{
|
||||
delay(5000);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
b = AGS.setUGM3Mode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
|
||||
uint8_t version = AGS.getSensorVersion();
|
||||
Serial.print("VERS:\t");
|
||||
Serial.println(version);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(3000);
|
||||
uint32_t value = AGS.readUGM3();
|
||||
Serial.print("UGM3:\t");
|
||||
Serial.print(value);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,164 @@
|
||||
//
|
||||
// FILE: AGS02MA_calibrate.ino
|
||||
// AUTHOR: Rob Tillaart, Beanow
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
// You can decrease/disable warmup when you're certain the chip already warmed up.
|
||||
#define WARMUP_MINUTES 6
|
||||
#define READ_INTERVAL 3000
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
uint8_t version;
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Serial.print("WARMUP:\t\t");
|
||||
Serial.println(WARMUP_MINUTES);
|
||||
Serial.print("INTERVAL:\t");
|
||||
Serial.println(READ_INTERVAL);
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t\t");
|
||||
Serial.println(b);
|
||||
|
||||
Serial.print("VERSION:\t");
|
||||
version = AGS.getSensorVersion();
|
||||
Serial.println(version);
|
||||
int err = AGS.lastError();
|
||||
|
||||
// Reading version correctly matters, as we display additional comments based on it.
|
||||
if(err != AGS02MA_OK)
|
||||
{
|
||||
Serial.print("Error reading version:\t");
|
||||
Serial.println(err);
|
||||
Serial.println("Won't attempt to calibrate. Reset when connection with the sensor is stable.");
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
|
||||
b = AGS.setPPBMode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
|
||||
Serial.println();
|
||||
Serial.print("Place the device outside in open air for ");
|
||||
Serial.print(WARMUP_MINUTES);
|
||||
Serial.println(" minute(s).");
|
||||
Serial.println("Make sure your device has warmed up sufficiently for the best results.");
|
||||
Serial.println("The PPB values should be stable (may include noise) not constantly decreasing.");
|
||||
Serial.println();
|
||||
|
||||
start = millis();
|
||||
stop = WARMUP_MINUTES * 60000UL;
|
||||
while(millis() - start < stop)
|
||||
{
|
||||
Serial.print("[PRE ]\t");
|
||||
printPPB();
|
||||
delay(READ_INTERVAL);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.println("About to perform calibration now.");
|
||||
|
||||
AGS02MA::ZeroCalibrationData initialValue;
|
||||
if (!AGS.getZeroCalibrationData(initialValue))
|
||||
{
|
||||
Serial.print("Error reading zero calibration data:\t");
|
||||
Serial.println(AGS.lastError());
|
||||
Serial.println("Won't attempt to calibrate. Reset when connection with the sensor is stable.");
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Your previous calibration data was:");
|
||||
printZeroCalibrationData(initialValue);
|
||||
|
||||
delay(1000);
|
||||
|
||||
// returns 1 if successful written
|
||||
b = AGS.zeroCalibration();
|
||||
Serial.println();
|
||||
Serial.print("CALIB:\t");
|
||||
Serial.println(b);
|
||||
Serial.println();
|
||||
Serial.println("Calibration done.");
|
||||
|
||||
AGS02MA::ZeroCalibrationData zc;
|
||||
while (!AGS.getZeroCalibrationData(zc))
|
||||
{
|
||||
Serial.print("Error:\t");
|
||||
Serial.print(AGS.lastError());
|
||||
Serial.println("\tretrying...");
|
||||
delay(READ_INTERVAL);
|
||||
}
|
||||
|
||||
Serial.println("Your new calibration data is:");
|
||||
printZeroCalibrationData(zc);
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Showing what PPB values look like post calibration.");
|
||||
// A 125 status is typically shown on v118's after they've been powered off.
|
||||
// Either having this version at all, or seeing this status, we'll display a notice.
|
||||
if (version == 118 || initialValue.status == 125)
|
||||
{
|
||||
Serial.println("NOTICE: v118 sensors are known to give different results after powering off!");
|
||||
Serial.println("You may need to manually set your calibration value every time power was lost.");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print("[POST]\t");
|
||||
printPPB();
|
||||
delay(READ_INTERVAL);
|
||||
}
|
||||
|
||||
|
||||
void printZeroCalibrationData(AGS02MA::ZeroCalibrationData &zc) {
|
||||
Serial.print("Status:\t");
|
||||
Serial.println(zc.status);
|
||||
Serial.print("Value:\t");
|
||||
Serial.println(zc.value);
|
||||
}
|
||||
|
||||
|
||||
void printPPB()
|
||||
{
|
||||
uint32_t value = AGS.readPPB();
|
||||
Serial.print("PPB:\t");
|
||||
Serial.print(value);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,172 @@
|
||||
//
|
||||
// FILE: AGS02MA_calibrate_manual.ino
|
||||
// AUTHOR: Rob Tillaart, Beanow
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
// The zero calibration value we'll (temporarily) set in the example.
|
||||
#define ZC_VALUE 700
|
||||
|
||||
#define READS 10
|
||||
#define INTERVAL 3000
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
AGS02MA::ZeroCalibrationData initialValue;
|
||||
uint8_t version;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Serial.print("READS:\t\t");
|
||||
Serial.println(READS);
|
||||
Serial.print("INTERVAL:\t");
|
||||
Serial.println(INTERVAL);
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t\t");
|
||||
Serial.println(b);
|
||||
|
||||
Serial.print("VERSION:\t");
|
||||
version = AGS.getSensorVersion();
|
||||
Serial.println(version);
|
||||
int err = AGS.lastError();
|
||||
|
||||
// Reading version correctly matters, as we display additional comments based on it.
|
||||
if(err != AGS02MA_OK)
|
||||
{
|
||||
Serial.print("Error reading version:\t");
|
||||
Serial.println(err);
|
||||
Serial.println("Won't attempt to calibrate. Reset when connection with the sensor is stable.");
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
|
||||
if (version != 118)
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("Only v118 sensors support manual zero calibration. For other versions, you can use the 'AGS02MA_calibrate' example instead.");
|
||||
}
|
||||
else
|
||||
{
|
||||
b = AGS.setPPBMode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
|
||||
while (!AGS.getZeroCalibrationData(initialValue))
|
||||
{
|
||||
onError(AGS.lastError());
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Your initial zero calibration is:");
|
||||
printZeroCalibrationData(initialValue);
|
||||
Serial.println();
|
||||
|
||||
Serial.println("Showing sample data before changing.");
|
||||
for (size_t i = 0; i < READS; i++)
|
||||
{
|
||||
delay(INTERVAL);
|
||||
printPPB();
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Manually setting zero calibration:");
|
||||
b = AGS.manualZeroCalibration(ZC_VALUE);
|
||||
Serial.print("CALIB:\t");
|
||||
Serial.println(b);
|
||||
|
||||
AGS02MA::ZeroCalibrationData newValue;
|
||||
while (!AGS.getZeroCalibrationData(newValue))
|
||||
{
|
||||
onError(AGS.lastError());
|
||||
}
|
||||
|
||||
printZeroCalibrationData(newValue);
|
||||
Serial.println();
|
||||
|
||||
Serial.println("Showing sample data.");
|
||||
Serial.println("NOTICE: v118 sensors are known to give different results after powering off!");
|
||||
Serial.println("You may need to manually set your calibration value every time power was lost.");
|
||||
for (size_t i = 0; i < READS; i++)
|
||||
{
|
||||
delay(INTERVAL);
|
||||
printPPB();
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Restoring initial zero calibration:");
|
||||
b = AGS.manualZeroCalibration(initialValue.value);
|
||||
Serial.print("CALIB:\t");
|
||||
Serial.println(b);
|
||||
|
||||
AGS02MA::ZeroCalibrationData restoredValue;
|
||||
while (!AGS.getZeroCalibrationData(restoredValue))
|
||||
{
|
||||
onError(AGS.lastError());
|
||||
}
|
||||
|
||||
printZeroCalibrationData(restoredValue);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(INTERVAL);
|
||||
printPPB();
|
||||
}
|
||||
|
||||
|
||||
void onError(int err) {
|
||||
Serial.print("Error:\t");
|
||||
Serial.print(err);
|
||||
Serial.println("\tretrying...");
|
||||
delay(INTERVAL);
|
||||
}
|
||||
|
||||
|
||||
void printZeroCalibrationData(AGS02MA::ZeroCalibrationData &zc) {
|
||||
Serial.print("Status:\t");
|
||||
Serial.println(zc.status);
|
||||
Serial.print("Value:\t");
|
||||
Serial.println(zc.value);
|
||||
}
|
||||
|
||||
|
||||
void printPPB()
|
||||
{
|
||||
uint32_t value = AGS.readPPB();
|
||||
Serial.print("PPB:\t");
|
||||
Serial.print(value);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,28 @@
|
||||
platforms:
|
||||
rpipico:
|
||||
board: rp2040:rp2040:rpipico
|
||||
package: rp2040:rp2040
|
||||
gcc:
|
||||
features:
|
||||
defines:
|
||||
- ARDUINO_ARCH_RP2040
|
||||
warnings:
|
||||
flags:
|
||||
|
||||
packages:
|
||||
rp2040:rp2040:
|
||||
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
# - uno
|
||||
# - due
|
||||
# - zero
|
||||
# - leonardo
|
||||
# - m4
|
||||
# - esp32
|
||||
# - esp8266
|
||||
# - mega2560
|
||||
# - rpipico
|
||||
|
||||
@ -0,0 +1,108 @@
|
||||
//
|
||||
// FILE: AGS02MA_get_registers.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: low level develop application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
//
|
||||
// PURPOSE: this is a debugging tool for developing / investigating.
|
||||
// Do not use it unless you are willing to crash your sensor.
|
||||
//
|
||||
// usage: make _readRegister(), _writeRegister() and _buffer public
|
||||
//
|
||||
// USE AT OWN RISK
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
uint8_t version = AGS.getSensorVersion();
|
||||
Serial.print("VERS:\t");
|
||||
Serial.println(version);
|
||||
|
||||
// AGS._buffer[0] = 0;
|
||||
// AGS._buffer[1] = 13;
|
||||
// AGS._buffer[2] = 14;
|
||||
// AGS._buffer[3] = 90;
|
||||
// AGS._buffer[5] = 248;
|
||||
// int x = AGS._writeRegister(0x01); // does not work.
|
||||
// Serial.println(x);
|
||||
|
||||
for (uint8_t reg = 0; reg < 9; reg++)
|
||||
{
|
||||
dumpRegister(reg);
|
||||
}
|
||||
dumpRegister(0x11);
|
||||
dumpRegister(0x20);
|
||||
dumpRegister(0x21);
|
||||
|
||||
AGS.setPPBMode();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// dumpRegister(0);
|
||||
// uint32_t zero = dumpRegister(1);
|
||||
// uint32_t x = dumpRegister(0x20); // seems to be the raw value.
|
||||
// delay(100);
|
||||
// uint32_t y = AGS.readPPB();
|
||||
// Serial.print(zero);
|
||||
// Serial.print("\t");
|
||||
// Serial.print(x);
|
||||
// Serial.print("\t");
|
||||
// Serial.print(y);
|
||||
// Serial.print("\t");
|
||||
// Serial.print((1.0 * x) / y, 2);
|
||||
// Serial.print("\t");
|
||||
// Serial.print((zero - x) / 350);
|
||||
// Serial.println();
|
||||
// Serial.println();
|
||||
// delay(2000);
|
||||
}
|
||||
|
||||
|
||||
uint32_t dumpRegister(uint8_t reg)
|
||||
{
|
||||
Serial.print("REG[");
|
||||
Serial.print(reg);
|
||||
Serial.print("]");
|
||||
|
||||
bool b = AGS._readRegister(reg);
|
||||
uint32_t value = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS._buffer[i]);
|
||||
|
||||
value *= 256;
|
||||
value += AGS._buffer[i];
|
||||
}
|
||||
Serial.print("\t");
|
||||
Serial.print(value);
|
||||
|
||||
Serial.println();
|
||||
delay(100);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,59 @@
|
||||
//
|
||||
// FILE: AGS02MA_minimal.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
//
|
||||
// default register is 0x00 at start of the sensor
|
||||
// datasheet states one can get the value with minimal interaction.
|
||||
// note this sketch does not use the library!
|
||||
|
||||
|
||||
#include "Wire.h"
|
||||
|
||||
|
||||
uint8_t buffer[5];
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
// Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
// Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(30400); // lowest speed an UNO supports that works with sensor.
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(3000);
|
||||
Wire.requestFrom(26, 5);
|
||||
for ( int i = 0; i < 5; i++)
|
||||
{
|
||||
buffer[i] = Wire.read();
|
||||
// Serial.print(buffer[i], HEX); // for debugging.
|
||||
// Serial.print('\t');
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// CONVERT RAW DATA
|
||||
Serial.print("STAT:\t");
|
||||
Serial.println(buffer[0]);
|
||||
Serial.print("PPB:\t");
|
||||
Serial.println(buffer[1] * 65536UL + buffer[2] * 256 + buffer[3]);
|
||||
Serial.print("CRC:\t");
|
||||
Serial.println(buffer[4]);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,69 @@
|
||||
//
|
||||
// FILE: AGS02MA_minimal_plotter.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application not using the library
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
//
|
||||
// default register is 0x00 at start of the sensor
|
||||
// datasheet states one can get the value with minimal interaction.
|
||||
// note this sketch does not use the library!
|
||||
|
||||
|
||||
#include "Wire.h"
|
||||
|
||||
|
||||
uint8_t buffer[5];
|
||||
|
||||
uint8_t cnt = 0;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
// Serial.println();
|
||||
// Serial.println(__FILE__);
|
||||
// Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
// Serial.println(AGS02MA_LIB_VERSION);
|
||||
// Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(30400); // lowest speed an UNO supports that works with sensor.
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Wire.requestFrom(26, 5);
|
||||
for ( int i = 0; i < 5; i++)
|
||||
{
|
||||
buffer[i] = Wire.read();
|
||||
// Serial.print(buffer[i], HEX); // for debugging.
|
||||
// Serial.print('\t');
|
||||
}
|
||||
// Serial.println();
|
||||
|
||||
if (cnt == 0)
|
||||
{
|
||||
// CONVERT RAW DATA
|
||||
Serial.println("\nSTAT\tPPB\tCRC");
|
||||
cnt = 20;
|
||||
}
|
||||
cnt--;
|
||||
if (buffer[0] == 0x10)
|
||||
{
|
||||
Serial.print(buffer[0]);
|
||||
Serial.print("\t");
|
||||
Serial.print(buffer[1] * 65536UL + buffer[2] * 256 + buffer[3]);
|
||||
Serial.print("\t");
|
||||
Serial.print(buffer[4]);
|
||||
Serial.println();
|
||||
delay(2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,123 @@
|
||||
//
|
||||
// FILE: AGS02MA_readRegister.ino
|
||||
// AUTHOR: Rob Tillaart, Beanow
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
const uint8_t addresses[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 0x11, 0x20, 0x21};
|
||||
|
||||
|
||||
AGS02MA::RegisterData reg;
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(3000);
|
||||
for (auto address : addresses)
|
||||
{
|
||||
bool b = AGS.readRegister(address, reg);
|
||||
Serial.print("REG[0x");
|
||||
Serial.print(address, HEX);
|
||||
Serial.print("]");
|
||||
|
||||
if(b)
|
||||
{
|
||||
printRegister(address, reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("\tError:\t");
|
||||
Serial.println(AGS.lastError());
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printRegister(uint8_t address, AGS02MA::RegisterData ®) {
|
||||
// Raw bytes first for any register.
|
||||
for (auto b : reg.data)
|
||||
{
|
||||
Serial.print("\t");
|
||||
Serial.print(b);
|
||||
}
|
||||
|
||||
Serial.print("\tCRC: ");
|
||||
Serial.print(reg.crcValid ? "OK " : "ERR ");
|
||||
Serial.print(reg.crc);
|
||||
|
||||
// Specific interpretations
|
||||
switch (address)
|
||||
{
|
||||
case 0x00:
|
||||
Serial.print("\tSensor data:\t");
|
||||
Serial.print(reg.data[0]);
|
||||
Serial.print("\t");
|
||||
Serial.print(
|
||||
(reg.data[1] << 16) +
|
||||
(reg.data[2] << 8) +
|
||||
reg.data[3]
|
||||
);
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
Serial.print("\tCalibration:\t");
|
||||
Serial.print(
|
||||
(reg.data[0] << 8) +
|
||||
reg.data[1]
|
||||
);
|
||||
Serial.print("\t");
|
||||
Serial.print(
|
||||
(reg.data[2] << 8) +
|
||||
reg.data[3]
|
||||
);
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
Serial.print("\tVersion:\t");
|
||||
Serial.print(reg.data[3]);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
Serial.print("\tI2C address:\t0x");
|
||||
Serial.print(reg.data[0], HEX);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,60 @@
|
||||
//
|
||||
// FILE: AGS02MA_setAddress.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
b = AGS.setAddress(42);
|
||||
Serial.print("SET_ADDR:\t");
|
||||
Serial.print(b, HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
|
||||
uint8_t addr = AGS.getAddress();
|
||||
Serial.print("GET_ADDR:\t");
|
||||
Serial.print(addr, HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
|
||||
Serial.println("\ndone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,55 @@
|
||||
//
|
||||
// FILE: AGS02MA_test.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
b = AGS.setPPBMode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
|
||||
uint8_t version = AGS.getSensorVersion();
|
||||
Serial.print("VERS:\t");
|
||||
Serial.println(version);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(2000);
|
||||
uint32_t value = AGS.readPPB();
|
||||
Serial.print("PPB:\t");
|
||||
Serial.println(value);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
# - uno
|
||||
# - leonardo
|
||||
# - due
|
||||
# - zero
|
||||
@ -0,0 +1,76 @@
|
||||
//
|
||||
// FILE: AGS02MA_test_CRC8.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
//
|
||||
// NOTE: this is a low level test for the communication / CRC
|
||||
// to have this example to work,
|
||||
// one need to make the _CRC8() and _buffer[]
|
||||
// public in the AGS02MA.h file.
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
uint8_t version = AGS.getSensorVersion();
|
||||
Serial.print("VERS:\t");
|
||||
Serial.println(version);
|
||||
dump("getSensorVersion");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(3000);
|
||||
AGS.setPPBMode();
|
||||
dump("MODE0");
|
||||
AGS.readPPB();
|
||||
dump("PPB");
|
||||
|
||||
delay(3000);
|
||||
AGS.setUGM3Mode();
|
||||
dump("MODE1");
|
||||
AGS.readUGM3();
|
||||
dump("UGM3");
|
||||
}
|
||||
|
||||
|
||||
void dump(char * str)
|
||||
{
|
||||
Serial.print(str);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS._buffer[i], HEX);
|
||||
}
|
||||
Serial.print('\t');
|
||||
Serial.print(AGS._CRC8(AGS._buffer, 4), HEX);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
105
lib/lib_i2c/AGS02MA-0.4.3/examples/issue/issue.ino
Normal file
105
lib/lib_i2c/AGS02MA-0.4.3/examples/issue/issue.ino
Normal file
@ -0,0 +1,105 @@
|
||||
//
|
||||
// FILE: AGS02MA_PPB.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
uint32_t rounds = 0;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
Serial.print("VERSION:\t");
|
||||
Serial.println(AGS.getSensorVersion());
|
||||
|
||||
Serial.print("DATE:\t");
|
||||
Serial.println(AGS.getSensorDate(), HEX);
|
||||
|
||||
// pre-heating improves measurement quality
|
||||
// can be skipped
|
||||
// Serial.println("\nWarming up (120 seconds = 24 dots)");
|
||||
// while (AGS.isHeated() == false)
|
||||
// {
|
||||
// delay(5000);
|
||||
// Serial.print(".");
|
||||
// }
|
||||
// Serial.println();
|
||||
|
||||
uint8_t version = AGS.getSensorVersion();
|
||||
Serial.print("VERS:\t");
|
||||
Serial.println(version);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(3000);
|
||||
|
||||
uint8_t kind = rounds % 20;
|
||||
|
||||
// Switch mode every 10 and 20 rounds.
|
||||
bool b;
|
||||
if (kind == 0) {
|
||||
b = AGS.setPPBMode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
} else if (kind == 10) {
|
||||
b = AGS.setUGM3Mode();
|
||||
uint8_t m = AGS.getMode();
|
||||
Serial.print("MODE:\t");
|
||||
Serial.print(b);
|
||||
Serial.print("\t");
|
||||
Serial.println(m);
|
||||
}
|
||||
|
||||
// Read PPB in first half of a 20-round cycle.
|
||||
if (kind < 10) {
|
||||
uint32_t value = AGS.readPPB();
|
||||
Serial.print("PPB:\t");
|
||||
Serial.print(value);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
} else {
|
||||
uint32_t value = AGS.readUGM3();
|
||||
Serial.print("UGM3:\t");
|
||||
Serial.print(value);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastStatus(), HEX);
|
||||
Serial.print("\t");
|
||||
Serial.print(AGS.lastError(), HEX);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
rounds++;
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
# - uno
|
||||
# - leonardo
|
||||
# - due
|
||||
# - zero
|
||||
83
lib/lib_i2c/AGS02MA-0.4.3/examples/test_CRC8/test_CRC8.ino
Normal file
83
lib/lib_i2c/AGS02MA-0.4.3/examples/test_CRC8/test_CRC8.ino
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// FILE: test_CRC8.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test application
|
||||
// URL: https://github.com/RobTillaart/AGS02MA
|
||||
//
|
||||
// just for develop scratch pad
|
||||
// need to make the CRC function public in the library
|
||||
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
|
||||
AGS02MA AGS(26);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// ESP devices typically miss the first serial log lines after flashing.
|
||||
// Delay somewhat to include all output.
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AGS02MA_LIB_VERSION: ");
|
||||
Serial.println(AGS02MA_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
bool b = AGS.begin();
|
||||
Serial.print("BEGIN:\t");
|
||||
Serial.println(b);
|
||||
|
||||
uint8_t _buffer[8];
|
||||
|
||||
_buffer[0] = 0x00;
|
||||
_buffer[1] = 0x0C;
|
||||
_buffer[2] = 0xFF;
|
||||
_buffer[3] = 0xF3;
|
||||
_buffer[4] = 0xFC;
|
||||
Serial.println(AGS._CRC8(_buffer, 5), HEX);
|
||||
|
||||
|
||||
_buffer[0] = 0x02;
|
||||
_buffer[1] = 0xFD;
|
||||
_buffer[2] = 0x02;
|
||||
_buffer[3] = 0xFD;
|
||||
_buffer[4] = 0x00;
|
||||
Serial.println(AGS._CRC8(_buffer, 5), HEX);
|
||||
|
||||
_buffer[0] = 0x00;
|
||||
_buffer[1] = 0xFF;
|
||||
_buffer[2] = 0x00;
|
||||
_buffer[3] = 0xFF;
|
||||
_buffer[4] = 0x30;
|
||||
Serial.println(AGS._CRC8(_buffer, 5), HEX);
|
||||
|
||||
_buffer[0] = 0x14;
|
||||
_buffer[1] = 0x14;
|
||||
_buffer[2] = 0x14;
|
||||
_buffer[3] = 0x1C;
|
||||
_buffer[4] = 0x75;
|
||||
Serial.println(AGS._CRC8(_buffer, 5), HEX);
|
||||
|
||||
_buffer[0] = 0x0;
|
||||
_buffer[1] = 0x0;
|
||||
_buffer[2] = 0xBB;
|
||||
Serial.println( _buffer[0] * 65536UL + _buffer[1] * 256 + _buffer[2]);
|
||||
_buffer[0] = 0x0;
|
||||
_buffer[1] = 0x01;
|
||||
_buffer[2] = 0xAE;
|
||||
Serial.println( _buffer[0] * 65536UL + _buffer[1] * 256 + _buffer[2]);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
60
lib/lib_i2c/AGS02MA-0.4.3/keywords.txt
Normal file
60
lib/lib_i2c/AGS02MA-0.4.3/keywords.txt
Normal file
@ -0,0 +1,60 @@
|
||||
# Syntax Colouring Map for AGS02MA
|
||||
|
||||
|
||||
# Data types (KEYWORD1)
|
||||
AGS02MA KEYWORD1
|
||||
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
begin KEYWORD2
|
||||
isConnected KEYWORD2
|
||||
reset KEYWORD2
|
||||
|
||||
isHeated KEYWORD2
|
||||
|
||||
setAddress KEYWORD2
|
||||
getAddress KEYWORD2
|
||||
|
||||
getSensorVersion KEYWORD2
|
||||
getSensorDate KEYWORD2
|
||||
|
||||
setI2CResetSpeed KEYWORD2
|
||||
getI2CResetSpeed KEYWORD2
|
||||
|
||||
zeroCalibration KEYWORD2
|
||||
manualZeroCalibration KEYWORD2
|
||||
getZeroCalibrationData KEYWORD2
|
||||
|
||||
setPPBMode KEYWORD2
|
||||
setUGM3Mode KEYWORD2
|
||||
getMode KEYWORD2
|
||||
|
||||
readPPB KEYWORD2
|
||||
readUGM3 KEYWORD2
|
||||
readPPM KEYWORD2
|
||||
readMGM3 KEYWORD2
|
||||
readUGF3 KEYWORD2
|
||||
|
||||
lastPPM KEYWORD2
|
||||
lastPPB KEYWORD2
|
||||
lastUGM3 KEYWORD2
|
||||
|
||||
lastRead KEYWORD2
|
||||
lastError KEYWORD2
|
||||
lastStatus KEYWORD2
|
||||
dataReady KEYWORD2
|
||||
|
||||
readRegister KEYWORD2
|
||||
|
||||
|
||||
# Constants ( LITERAL1)
|
||||
AGS02MA_LIB_VERSION LITERAL1
|
||||
|
||||
AGS02MA_OK LITERAL1
|
||||
AGS02MA_ERROR LITERAL1
|
||||
AGS02MA_ERROR_CRC LITERAL1
|
||||
AGS02MA_ERROR_READ LITERAL1
|
||||
AGS02MA_I2C_CLOCK LITERAL1
|
||||
AGS02MA_ERROR_REQUEST LITERAL1
|
||||
|
||||
|
||||
29
lib/lib_i2c/AGS02MA-0.4.3/library.json
Normal file
29
lib/lib_i2c/AGS02MA-0.4.3/library.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "AGS02MA",
|
||||
"keywords": "I2C, AGS02MA, tvoc",
|
||||
"description": "Arduino library for AGS02MA - TVOC sensor.",
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Viktor Balint"
|
||||
},
|
||||
{
|
||||
"name": "Rob Tillaart",
|
||||
"email": "Rob.Tillaart@gmail.com",
|
||||
"maintainer": true
|
||||
},
|
||||
{
|
||||
"name": "Beanow"
|
||||
}
|
||||
],
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/AGS02MA.git"
|
||||
},
|
||||
"version": "0.4.3",
|
||||
"license": "MIT",
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
"headers": "AGS02MA.h"
|
||||
}
|
||||
11
lib/lib_i2c/AGS02MA-0.4.3/library.properties
Normal file
11
lib/lib_i2c/AGS02MA-0.4.3/library.properties
Normal file
@ -0,0 +1,11 @@
|
||||
name=AGS02MA
|
||||
version=0.4.3
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library for AGS02MA - TVOC sensor
|
||||
paragraph=Note it uses slow I2C < 30KHz. See readme.md
|
||||
category=Sensors
|
||||
url=https://github.com/RobTillaart/AGS02MA.git
|
||||
architectures=*
|
||||
includes=AGS02MA.h
|
||||
depends=
|
||||
102
lib/lib_i2c/AGS02MA-0.4.3/test/unit_test_001.cpp
Normal file
102
lib/lib_i2c/AGS02MA-0.4.3/test/unit_test_001.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2021-08-12
|
||||
// PURPOSE: unit tests for the AGS02MA TVOC sensor
|
||||
// https://github.com/RobTillaart/AGS02MA
|
||||
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "AGS02MA.h"
|
||||
|
||||
// writing to a virtual device does not work
|
||||
// as millis() function is not implemented in
|
||||
// the Arduino-CI environment
|
||||
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
fprintf(stderr, "AGS02MA_LIB_VERSION: %s\n", (char *) AGS02MA_LIB_VERSION);
|
||||
}
|
||||
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constants)
|
||||
{
|
||||
assertEqual( 0, AGS02MA_OK);
|
||||
assertEqual(-10, AGS02MA_ERROR);
|
||||
assertEqual(-11, AGS02MA_ERROR_CRC);
|
||||
assertEqual(-12, AGS02MA_ERROR_READ);
|
||||
assertEqual(-13, AGS02MA_ERROR_NOT_READY);
|
||||
assertEqual(-14, AGS02MA_ERROR_REQUEST);
|
||||
|
||||
assertEqual(25000, AGS02MA_I2C_CLOCK);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_base)
|
||||
{
|
||||
AGS02MA AGS(26);
|
||||
Wire.begin();
|
||||
|
||||
assertTrue(AGS.begin());
|
||||
assertTrue(AGS.isConnected()); // TODO - GODMODE
|
||||
|
||||
assertFalse(AGS.isHeated());
|
||||
assertEqual(0, AGS.lastRead());
|
||||
|
||||
assertEqual(26, AGS.getAddress());
|
||||
//assertTrue(AGS.setAddress(42));
|
||||
//assertEqual(42, AGS.getAddress());
|
||||
|
||||
assertEqual(100000, AGS.getI2CResetSpeed());
|
||||
AGS.setI2CResetSpeed(400000);
|
||||
assertEqual(400000, AGS.getI2CResetSpeed());
|
||||
|
||||
assertEqual(0, AGS.lastError());
|
||||
assertEqual(0, AGS.lastStatus());
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mode)
|
||||
{
|
||||
AGS02MA AGS(26);
|
||||
Wire.begin();
|
||||
|
||||
assertTrue(AGS.begin());
|
||||
assertTrue(AGS.isConnected()); // TODO - GODMODE
|
||||
|
||||
assertEqual(255, AGS.getMode());
|
||||
|
||||
// assertTrue(AGS.setPPBMode());
|
||||
// assertEqual(0, AGS.getMode());
|
||||
|
||||
// assertTrue(AGS.setUGM3Mode());
|
||||
// assertEqual(1, AGS.getMode());
|
||||
}
|
||||
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// -- END OF FILE --
|
||||
@ -807,6 +807,8 @@
|
||||
// #define USE_RX8030 // [I2cDriver90] Enable RX8030 RTC - used by #23855 - support both I2C buses on ESP32 (I2C address 0x32) (+0k7 code)
|
||||
// #define USE_PCF85063 // [I2cDriver92] Enable PCF85063 RTC support (I2C address 0x51)
|
||||
|
||||
// #define USE_AGS02MA // [I2cDriver95] Enable AGS02MA Air Quality Sensor (I2C address 0x1A)
|
||||
|
||||
// #define USE_DISPLAY // Add I2C/TM1637/MAX7219 Display Support (+2k code)
|
||||
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
||||
#define USE_DISPLAY_LCD // [DisplayModel 1] [I2cDriver3] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code)
|
||||
|
||||
199
tasmota/tasmota_xsns_sensor/xsns_118_ags02ma.ino
Normal file
199
tasmota/tasmota_xsns_sensor/xsns_118_ags02ma.ino
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
xsns_118_ags02ma.ino - AGS02MA TVOC sensor support for Tasmota
|
||||
|
||||
Copyright (C) 2025 Akshaylal S
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_I2C
|
||||
#ifdef USE_AGS02MA
|
||||
/*********************************************************************************************\
|
||||
* AGS02MA - TVOC (Total Volatile Organic Compounds) Sensor
|
||||
*
|
||||
* Source: RobTillaart/AGS02MA library
|
||||
* Adaption for TASMOTA: Akshaylal S
|
||||
*
|
||||
* I2C Address: 0x1A
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XSNS_118 118
|
||||
#define XI2C_95 95 // See I2CDEVICES.md
|
||||
|
||||
#define AGS02MA_ADDRESS 0x1A
|
||||
|
||||
#include "AGS02MA.h"
|
||||
|
||||
enum AGS02MA_State {
|
||||
STATE_AGS02MA_START,
|
||||
STATE_AGS02MA_INIT,
|
||||
STATE_AGS02MA_HEATING,
|
||||
STATE_AGS02MA_NORMAL,
|
||||
STATE_AGS02MA_FAIL,
|
||||
};
|
||||
|
||||
AGS02MA *ags02ma = nullptr;
|
||||
AGS02MA_State ags02ma_state = STATE_AGS02MA_START;
|
||||
|
||||
bool ags02ma_init = false;
|
||||
bool ags02ma_read_pend = false;
|
||||
|
||||
uint32_t ags02ma_ppb_value = 0;
|
||||
uint16_t heating_counter = 0; // Counter for heating period (120 seconds / 24 checks = 5 seconds per check)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void Ags02maInit(void)
|
||||
{
|
||||
if (!I2cSetDevice(AGS02MA_ADDRESS)) { return; }
|
||||
|
||||
ags02ma = new AGS02MA(AGS02MA_ADDRESS, &I2cGetWire());
|
||||
|
||||
bool b = ags02ma->begin();
|
||||
if (!b) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("AGS02MA: Sensor not found or initialization failed"));
|
||||
ags02ma_state = STATE_AGS02MA_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t version = ags02ma->getSensorVersion();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("AGS02MA: Sensor version 0x%02X"), version);
|
||||
|
||||
// Set PPB mode
|
||||
b = ags02ma->setPPBMode();
|
||||
if (!b) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("AGS02MA: Failed to set PPB mode"));
|
||||
ags02ma_state = STATE_AGS02MA_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t mode = ags02ma->getMode();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("AGS02MA: Mode set to %d"), mode);
|
||||
|
||||
I2cSetActiveFound(AGS02MA_ADDRESS, "AGS02MA", XI2C_95);
|
||||
|
||||
ags02ma_init = true;
|
||||
ags02ma_state = STATE_AGS02MA_HEATING;
|
||||
heating_counter = 0;
|
||||
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("AGS02MA: Starting warm-up period (120 seconds)"));
|
||||
}
|
||||
|
||||
void Ags02maUpdate(void)
|
||||
{
|
||||
if (ags02ma_state == STATE_AGS02MA_FAIL) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AGS02MA: In FAIL state"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle heating period
|
||||
if (ags02ma_state == STATE_AGS02MA_HEATING) {
|
||||
// Check every 5 seconds (called from FUNC_EVERY_SECOND, so count to 5)
|
||||
if (heating_counter % 5 == 0) {
|
||||
if (ags02ma->isHeated()) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("AGS02MA: Warm-up complete, sensor ready"));
|
||||
ags02ma_state = STATE_AGS02MA_NORMAL;
|
||||
heating_counter = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
heating_counter++;
|
||||
|
||||
// Log progress every 24 seconds (approximately)
|
||||
if (heating_counter % 24 == 0) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AGS02MA: Warming up... %d seconds elapsed"), heating_counter);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal operation - read sensor value
|
||||
if (ags02ma_state == STATE_AGS02MA_NORMAL) {
|
||||
ags02ma_ppb_value = ags02ma->readPPB();
|
||||
|
||||
uint8_t status = ags02ma->lastStatus();
|
||||
uint8_t error = ags02ma->lastError();
|
||||
|
||||
if (error != 0) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AGS02MA: Read error - Status: 0x%02X, Error: 0x%02X"), status, error);
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("AGS02MA: PPB value: %d"), ags02ma_ppb_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_SNS_AGS02MA[] PROGMEM =
|
||||
"{s}AGS02MA " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
#endif
|
||||
|
||||
void Ags02maShow(bool json)
|
||||
{
|
||||
if (ags02ma_state == STATE_AGS02MA_NORMAL) {
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"AGS02MA\":{\"" D_JSON_TVOC "\":%d}"),
|
||||
ags02ma_ppb_value);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (0 == TasmotaGlobal.tele_period) {
|
||||
DomoticzSensor(DZ_AIRQUALITY, ags02ma_ppb_value);
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_SNS_AGS02MA, ags02ma_ppb_value);
|
||||
#endif
|
||||
}
|
||||
} else if (ags02ma_state == STATE_AGS02MA_HEATING) {
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"AGS02MA\":{\"Status\":\"Heating\"}"));
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_PD(PSTR("{s}AGS02MA Status{m}Warming up...{e}"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xsns118(uint32_t function)
|
||||
{
|
||||
if (!I2cEnabled(XI2C_95)) { return false; }
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (FUNC_INIT == function) {
|
||||
Ags02maInit();
|
||||
}
|
||||
else if (ags02ma_init) {
|
||||
switch (function) {
|
||||
case FUNC_EVERY_SECOND:
|
||||
Ags02maUpdate();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
Ags02maShow(1);
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
Ags02maShow(0);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_AGS02MA
|
||||
#endif // USE_I2C
|
||||
Loading…
Reference in New Issue
Block a user