Closed FLXMM closed 3 years ago
Take a look at https://github.com/xoseperez/espurna/commit/b500273029d1c8e8bb14d88751960c7f76900268#diff-55ad6784b09d44d0f6e35b8d8914794a (https://github.com/xoseperez/espurna/pull/2216)
You can follow the existing library example and integrate them into the reading loop. Sensor class announces what values it holds via _count member var and type(index), return the value types you want under the specific index. After that value(index) will be used to read them
Thanks for the feedback. But tbh my expertice in coding is sooo little the looking at your answer and investigating the files I still dont know what to do. My "coding skills" consist of copy and pasting things to customize what i want :P
This is nearly what I proposed :)
Example code lists 2 possible readings: https://github.com/xoseperez/espurna/blob/f6ec2422a49f303658cd2d96fb6c3d14cab861a1/code/espurna/config/types.h#L382 https://github.com/xoseperez/espurna/blob/f6ec2422a49f303658cd2d96fb6c3d14cab861a1/code/espurna/config/types.h#L364
For example, we will use Adafruit lib, so we would need to copy example's behaviour: https://github.com/adafruit/Adafruit_CCS811/blob/master/examples/CCS811_test/CCS811_test.ino
pre()
routine would adapt to what example loop()
does:
void pre() override {
_error = SENSOR_ERROR_WARM_UP;
if (!_ccs.available()) return;
if (!_ccs.readData()) return;
_error = SENSOR_ERROR_OK;
_eco2 = _ccs.geteCO2();
_tvoc = _ccs.getTVOC();
}
Reading will use cached values:
double value(unsigned char index) override {
switch (index) {
case 0: return _eco2;
case 1: return _tvoc;
default: return 0.0;
}
}
As I mentioned earlier, we need specific indexes mapped correctly so the above works:
unsigned char type(unsigned char index) override {
switch (index) {
case 0: return MAGNITUDE_CO2;
case 1: return MAGNITUDE_VOC;
default: return MAGNITUDE_NONE;
}
}
Implementation minutiae is that we also need _count
to be correctly set right when class is constructed. For example, we created sensors/CCS811Sensor.h
and have these:
#include "BaseSensor.h"
#include <Adafruit_CCS811.h>
class CCS811Sensor : public BaseSensor {
public:
CCS811Sensor() {
_count = 2;
}
void begin() override {
_ccs.begin();
_ready = true;
}
// the rest of the sensor which we implemented above
private:
Adafruit_CCS811 _ccs;
uint16_t _eco2 { 0u );
uint16_t _tvoc { 0u };
};
At the end, we include this sensor header in the sensor.cpp
and add _sensors.push_back(new CCS811Sensor());
and the end of the sensor loading routine (just search for _sensors.push_back(
). We don't need any complex setup, so we just create the object and that's it.
(I have not tested if this works though, but I am sure mistakes are easy to spot after trying to build this)
first of all thank you very much @mcspr . for the more detailed description. It made me look deeper into stuff like BaseSensor etc. But unfortanetly it didnt solve my issue. Everything compiles fine. But i dont see any sensor values in the webinterface and no info in the debug log of the webinterface.
So I have no clue where to start or identifying what to change.
I did the following:
1st I added : https://github.com/adafruit/Adafruit_CCS811 to the platform.ini
and
in sensor.cpp
_sensors.push_back(sensor);
_sensors.push_back(new CCS811Sensor());
}
#endif`
and I created this file sensors/CCS811Sensor.h
as mentioned in your description:
#include "BaseSensor.h"
#include <Adafruit_CCS811.h>
class CCS811Sensor : public BaseSensor {
public:
CCS811Sensor() {
_count = 2;
}
void begin() override {
_ccs.begin();
_ready = true;
}
unsigned char type(unsigned char index) override {
switch (index) {
case 0: return MAGNITUDE_CO2;
case 1: return MAGNITUDE_VOC;
default: return MAGNITUDE_NONE;
}
}
void pre() override {
_error = SENSOR_ERROR_WARM_UP;
if (!_ccs.available()) return;
if (!_ccs.readData()) return;
_error = SENSOR_ERROR_OK;
_eco2 = _ccs.geteCO2();
_tvoc = _ccs.getTVOC();
}
double value(unsigned char index) override {
switch (index) {
case 0: return _eco2;
case 1: return _tvoc;
default: return 0.0;
}
}
// the rest of the sensor which we implemented above
private:
Adafruit_CCS811 _ccs;
uint16_t _eco2 { 0u };
uint16_t _tvoc { 0u };
};
does this make at all sense?? Or am I missing something very important? You are using BaseSensor
can it be problem that the CCS811 is a I2CSensor
? I am not sure if this important or not but I want to run 2 I2C sensors (different address) on an Sonoff S20 (itead 20)
Note of #if SOMETHING ... #endif
blocks, it seems you included the push_back(...)
code inside of PZEM004V3_SUPPORT
block which is not enabled, so while it builds it never gets to include the CCS811Sensor code. So it is something like:
diff --git a/code/espurna/sensor.cpp b/code/espurna/sensor.cpp
index 7162cf5e..7201e768 100644
--- a/code/espurna/sensor.cpp
+++ b/code/espurna/sensor.cpp
@@ -2190,6 +2192,8 @@ void _sensorLoad() {
}
#endif
+ _sensors.push_back(new CCS811Sensor());
+
}
String _magnitudeTopicIndex(const sensor_magnitude_t& magnitude) {
I missed some required override
methods btw (what compiler will describe as pure virtual functions that are missing in the CCS811Sensor class):
String description() override {
return String(F("CCS811"));
}
String description(unsigned char) override {
return description();
}
String address(unsigned char) override {
return String(F("0x5a")); // TODO: this does not do anything useful atm
}
Perhaps, it would be also nice to do
void begin() override {
_ready = _ccs.begin();
}
to notify about any initial issues with the connection and to re-do the .begin() call until it is successful.
I2CSensor
is indented for the things we implement ourselves (like BMX280, for example) and to ensure we don't have conflicting addresses with multiple sensors, but Adafruit lib already manages the i2c connection after _ccs.begin()
and we don't need this atm.
Another thing I have not mentioned before... since this is an ad-hoc sensor class, we also need to manually specify -DSENSOR_SUPPORT=1
so the sensor.cpp actually builds.
e.g. env ESPURNA_FLAGS='-DNODEMCU_LOLIN -DSENSOR_SUPPORT=1' pio run -e esp8266-4m-base
@mcspr THX Max.. this helps a lot ..now it seems there is a connection :)
I am getting
[012016] [SENSOR] Error reading data from CCS811 (error: 2)
Displaying warmup
in the webinterface which as far as I see is from the sensor.cpp. (I abortet after 30minutes)
But from what i found out error 2 refers to:
2 MEASMODE_INVALID The CCS811 received an I²C request to write an unsupported mode to
MEAS_MODE
(https://cdn.sparkfun.com/assets/learn_tutorials/1/4/3/CCS811_Datasheet-DS000459.pdf)
But i have been trying to get a work that out but i dont know how to solve this. I check with nodemcu the test.ino for adafruit_CCS811 library and the sensor is working (also i had to delete the while(1)
from the test.ino
Do you have any idea what else I could try?
(error: 2) refers to this line in pre():
_error = SENSOR_ERROR_WARM_UP;
if (!_ccs.available()) return;
if (!_ccs.readData()) return;
_error = SENSOR_ERROR_OK;
So it is entirely from sw side, readData() does not have any data at the time we want it. But it should have something after 30 minutes though? I see that adafruit sets CCS811_DRIVE_MODE_1SEC aka every 1 second we should have available() -> true
edit: does removing the first _error = ...
show anything?
well that just gives me 0ppm
in webinterface and no info in debug
..so i dont know but when i thought ok whatever.. i looked at dummySensor.h again and just formatted your code to look like the DummySensor
.
#include "BaseSensor.h"
#include <Adafruit_CCS811.h>
class CCS811Sensor : public BaseSensor {
public:
CCS811Sensor() {
_count = 2;
}
/*void begin() override {
_ccs.begin();
_ready = true;
}
*/
void begin() override {
_ready = _ccs.begin();
_error = SENSOR_ERROR_OK;
}
String description() override {
static String CCS811 (F("CCS811"));
return CCS811;
}
String description(unsigned char) override {
return description();
}
String address(unsigned char) override {
static String CCS811(F("0x5a")); // TODO: this does not do anything useful atm
return CCS811;
}
unsigned char type(unsigned char index) override {
switch (index) {
case 0: return MAGNITUDE_CO2;
case 1: return MAGNITUDE_VOC;
}
return MAGNITUDE_NONE;
}
double value(unsigned char index) override {
switch (index) {
case 0: return _eco2;
case 1: return _tvoc;
}
return 0.0;
}
void pre() override {
if (_ccs.available()){
if (!_ccs.readData()){
_eco2 = _ccs.geteCO2();
_tvoc = _ccs.getTVOC();
}
}
}
// the rest of the sensor which we implemented above
private:
Adafruit_CCS811 _ccs;
uint16_t _eco2 { 0u };
uint16_t _tvoc { 0u };
};
Doing this and at the same time looking at the working tasmota code (https://github.com/arendst/Tasmota/blob/7dafeb280e08d64b7603d7204aebb816fb17714d/tasmota/xsns_31_ccs811.ino)
I recognized you where using !_ccs.available()
but in tasmota they use _ccs.available()
this might have been it.
Because know i get values :)))
SO THX again @mcspr and gn8
Reading the readData code again I see the thing they were trying to do and return false
kind of blindsided me when skimming the code previously. Reading the comment would've helped :) It really spells it out
returns 0 if no error, error code otherwise.
Hi all,
since I dont know how to compile espurna with external sensor libraries: is it possible to integrate the Sensor CCS811? Its an enviromental sensor measuring TVOCs. Air quality.
https://github.com/sciosense/CCS811_driver https://github.com/adafruit/Adafruit_CCS811 https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library
or can someone point me in the right direction of a tutorial? how i can integrate it my self? I couldnt find anything. Thank you