summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven <steven.vasilogianis@gmail.com>2021-10-05 21:24:08 -0400
committerSteven <steven.vasilogianis@gmail.com>2021-10-05 22:50:39 -0400
commit7ab9abd11e3ebe94f307b64728738b0789f97719 (patch)
treed157fa272450cc0236562ca7bfadbd72b6f8cfe2
parent0848a13c38d2f54c91a1e98e114fd49e3f4c8a70 (diff)
parenta6ac5a6e71fa4feadc60b9932eb898d59ca2f337 (diff)
WIP on master: 0848a13 Add photoresistor support
-rw-r--r--src/main/CCS811.cpp154
-rw-r--r--src/main/CCS811.h224
-rw-r--r--src/main/main.ino130
3 files changed, 456 insertions, 52 deletions
diff --git a/src/main/CCS811.cpp b/src/main/CCS811.cpp
new file mode 100644
index 0000000..05b71c0
--- /dev/null
+++ b/src/main/CCS811.cpp
@@ -0,0 +1,154 @@
1#include "CCS811.h"
2
3int CCS811::begin(void)
4{
5 uint8_t id=0;
6 Wire.begin();
7 softReset();
8 delay(100);
9 if(readReg(CCS811_REG_HW_ID,&id,1) != 1){DBG("");
10 DBG("bus data access error");DBG("");
11 return ERR_DATA_BUS;DBG("");
12 }
13
14 DBG("real sensor id=");DBG(id);
15 if(id != CCS811_HW_ID){DBG("");
16 delay(1);
17 return ERR_IC_VERSION;
18 }
19 writeReg(CCS811_BOOTLOADER_APP_START, NULL, 0);
20 setMeasurementMode(0,0,eMode4);
21 setInTempHum(25, 50);
22 return ERR_OK;
23}
24
25void CCS811::softReset(){
26 uint8_t value[4] = {0x11, 0xE5, 0x72, 0x8A};
27 writeReg(CCS811_REG_SW_RESET, value, 4);
28}
29
30bool CCS811::checkDataReady()
31{
32 int8_t status[1] = {0};
33 readReg(CCS811_REG_STATUS, status, 1);
34 DBG(status[0],HEX);
35 if(!((status[0] >> 3) & 0x01))
36 return false;
37 else
38 return true;
39}
40
41uint16_t CCS811::readBaseLine(){
42 uint8_t buffer[2];
43 readReg(CCS811_REG_BASELINE, buffer, 2);
44 return buffer[0]<<8|buffer[1];
45}
46
47void CCS811::writeBaseLine(uint16_t baseLine){
48 uint8_t buffer[2];
49
50 buffer[0] = baseLine>>8;
51 buffer[1] = baseLine;
52 writeReg(CCS811_REG_BASELINE, buffer, 2);
53}
54
55void CCS811::setMeasurementMode(uint8_t thresh, uint8_t interrupt, eDRIVE_MODE_t mode){
56 uint8_t measurement[1] = {0};
57 measurement[0] = (thresh << 2) | (interrupt << 3) | (mode << 4);
58 writeReg(CCS811_REG_MEAS_MODE, measurement, 1);
59}
60
61void CCS811::setMeasCycle(eCycle_t cycle){
62 uint8_t measurement[1] = {0};
63 measurement[0] = cycle << 4;
64 writeReg(CCS811_REG_MEAS_MODE, measurement, 1);
65}
66
67uint8_t CCS811::getMeasurementMode(){
68 uint8_t meas[1] = {0};
69 readReg(CCS811_REG_MEAS_MODE, meas, 1);
70 return meas[0];
71}
72
73void CCS811::setThresholds(uint16_t lowToMed, uint16_t medToHigh)
74{
75 uint8_t buffer[] = {(uint8_t)((lowToMed >> 8) & 0xF),
76 (uint8_t)(lowToMed & 0xF),
77 (uint8_t)((medToHigh >> 8) & 0xF),
78 (uint8_t)(medToHigh & 0xF)};
79
80 writeReg(CCS811_REG_THRESHOLDS, buffer, 5);
81 uint8_t buf[1];
82 readReg(CCS811_REG_THRESHOLDS, buf, 1);
83 Serial.println(buf[0],HEX);
84}
85
86uint16_t CCS811::getCO2PPM(){
87 uint8_t buffer[8];
88 readReg(CCS811_REG_ALG_RESULT_DATA, buffer, 8);
89 eCO2 = (((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1]);
90 return eCO2;
91}
92
93uint16_t CCS811::getTVOCPPB(){
94 uint8_t buffer[8];
95 readReg(CCS811_REG_ALG_RESULT_DATA, buffer, 8);
96 eTVOC = (((uint16_t)buffer[2] << 8) | (uint16_t)buffer[3]);
97 return eTVOC;
98}
99
100void CCS811::setInTempHum(float temperature, float humidity) // compensate for temperature and relative humidity
101{
102 int _temp, _rh;
103 if(temperature>0)
104 _temp = (int)temperature + 0.5; // this will round off the floating point to the nearest integer value
105 else if(temperature<0) // account for negative temperatures
106 _temp = (int)temperature - 0.5;
107 _temp = _temp + 25; // temperature high byte is stored as T+25°C in the sensor's memory so the value of byte is positive
108 _rh = (int)humidity + 0.5; // this will round off the floating point to the nearest integer value
109
110 uint8_t envData[4];
111
112 envData[0] = _rh << 1; // shift the binary number to left by 1. This is stored as a 7-bit value
113 envData[1] = 0; // most significant fractional bit. Using 0 here - gives us accuracy of +/-1%. Current firmware (2016) only supports fractional increments of 0.5
114 envData[2] = _temp << 1;
115 envData[3] = 0;
116
117 writeReg(CCS811_REG_ENV_DATA, &envData, 4);
118}
119
120void CCS811::writeReg(uint8_t reg, const void* pBuf, size_t size)
121{
122 if(pBuf == NULL){
123 DBG("pBuf ERROR!! : null pointer");
124 }
125 uint8_t * _pBuf = (uint8_t *)pBuf;
126 _pWire->beginTransmission(_deviceAddr);
127 _pWire->write(&reg, 1);
128
129 for(uint16_t i = 0; i < size; i++){
130 _pWire->write(_pBuf[i]);
131 }
132 _pWire->endTransmission();
133}
134
135uint8_t CCS811::readReg(uint8_t reg, const void* pBuf, size_t size)
136{
137 if(pBuf == NULL){
138 DBG("pBuf ERROR!! : null pointer");
139 }
140 uint8_t * _pBuf = (uint8_t *)pBuf;
141 _pWire->beginTransmission(_deviceAddr);
142 _pWire->write(&reg, 1);
143
144 if( _pWire->endTransmission() != 0){
145 return 0;
146 }
147
148 _pWire->requestFrom(_deviceAddr, (uint8_t) size);
149 for(uint16_t i = 0; i < size; i++){
150 _pBuf[i] = _pWire->read();
151 }
152 _pWire->endTransmission();
153 return size;
154}
diff --git a/src/main/CCS811.h b/src/main/CCS811.h
new file mode 100644
index 0000000..2640535
--- /dev/null
+++ b/src/main/CCS811.h
@@ -0,0 +1,224 @@
1#ifndef _CCS811_H
2#define _CCS811_H
3
4#if ARDUINO >= 100
5#include "Arduino.h"
6#else
7#include "WProgram.h"
8#endif
9#include <Wire.h>
10
11
12/*I2C ADDRESS*/
13#define CCS811_I2C_ADDRESS1 0x5A
14#define CCS811_I2C_ADDRESS2 0x5B
15
16#define CCS811_REG_STATUS 0x00
17#define CCS811_REG_MEAS_MODE 0x01
18#define CCS811_REG_ALG_RESULT_DATA 0x02
19#define CCS811_REG_RAW_DATA 0x03
20#define CCS811_REG_ENV_DATA 0x05
21#define CCS811_REG_NTC 0x06
22#define CCS811_REG_THRESHOLDS 0x10
23#define CCS811_REG_BASELINE 0x11
24#define CCS811_REG_HW_ID 0x20
25#define CCS811_REG_HW_VERSION 0x21
26#define CCS811_REG_FW_BOOT_VERSION 0x23
27#define CCS811_REG_FW_APP_VERSION 0x24
28#define CCS811_REG_INTERNAL_STATE 0xA0
29#define CCS811_REG_ERROR_ID 0xE0
30#define CCS811_REG_SW_RESET 0xFF
31
32#define CCS811_BOOTLOADER_APP_ERASE 0xF1
33#define CCS811_BOOTLOADER_APP_DATA 0xF2
34#define CCS811_BOOTLOADER_APP_VERIFY 0xF3
35#define CCS811_BOOTLOADER_APP_START 0xF4
36
37#define CCS811_HW_ID 0x81
38//Open the macro to see the detailed program execution process.
39//#define ENABLE_DBG
40
41#ifdef ENABLE_DBG
42#define DBG(...) {Serial.print("[");Serial.print(__FUNCTION__); Serial.print("(): "); Serial.print(__LINE__); Serial.print(" ] "); Serial.println(__VA_ARGS__);}
43#else
44#define DBG(...)
45#endif
46
47class CCS811
48{
49public:
50 #define ERR_OK 0 //OK
51 #define ERR_DATA_BUS -1 //error in data bus
52 #define ERR_IC_VERSION -2 //chip version mismatch
53
54 uint8_t _deviceAddr;
55 typedef enum{
56 eMode0, //Idle (Measurements are disabled in this mode)
57 eMode1, //Constant power mode, IAQ measurement every second
58 eMode2, //Pulse heating mode IAQ measurement every 10 seconds
59 eMode3, //Low power pulse heating mode IAQ measurement every 60 seconds
60 eMode4 //Constant power mode, sensor measurement every 250ms 1xx: Reserved modes (For future use)
61 }eDRIVE_MODE_t;
62
63 typedef enum{
64 eClosed, //Idle (Measurements are disabled in this mode)
65 eCycle_1s, //Constant power mode, IAQ measurement every second
66 eCycle_10s, //Pulse heating mode IAQ measurement every 10 seconds
67 eCycle_60s, //Low power pulse heating mode IAQ measurement every 60 seconds
68 eCycle_250ms //Constant power mode, sensor measurement every 250ms 1xx: Reserved modes (For future use)
69 }eCycle_t;
70 /**
71 * @brief Constructor
72 * @param Input in Wire address
73 */
74 CCS811(TwoWire *pWire = &Wire, uint8_t deviceAddr = 0x5A){_pWire = pWire; _deviceAddr = deviceAddr;};
75
76 /**
77 * @brief Constructor
78 * @return Return 0 if initialization succeeds, otherwise return non-zero.
79 */
80 int begin();
81 /**
82 * @brief Judge if there is data to read
83 * @return Return 1 if there is, otherwise return 0.
84 */
85 bool checkDataReady();
86 /**
87 * @brief Reset sensor, clear all configured data.
88 */
89 void softReset(),
90 /**
91 * @brief Set environment parameter
92 * @param temperature Set temperature value, unit: centigrade, range (-40~85℃)
93 * @param humidity Set humidity value, unit: RH, range (0~100)
94 */
95 setInTempHum(float temperature, float humidity),
96 /**
97 * @brief Measurement parameter configuration
98 * @param thresh:0 for Interrupt mode operates normally; 1 for interrupt mode only asserts the nINT signal (driven low) if the new
99 * @param interrupt:0 for Interrupt generation is disabled; 1 for the nINT signal is asserted (driven low) when a new sample is ready in
100 * @param mode:in typedef enum eDRIVE_MODE_t
101 */
102 setMeasurementMode(uint8_t thresh, uint8_t interrupt, eDRIVE_MODE_t mode),
103 /**
104 * @brief Measurement parameter configuration
105 * @param mode:in typedef enum eDRIVE_MODE_t
106 */
107 setMeasCycle(eCycle_t cycle),
108 /**
109 * @brief Set interrupt thresholds
110 * @param lowToMed: interrupt triggered value in range low to middle
111 * @param medToHigh: interrupt triggered value in range middle to high
112 */
113 setThresholds(uint16_t lowToMed, uint16_t medToHigh);
114 /**
115 * @brief Get current configured parameter
116 * @return configuration code, needs to be converted into binary code to analyze
117 * The 2nd: Interrupt mode (if enabled) operates normally,1: Interrupt mode (if enabled) only asserts the nINT signal (driven low) if the new
118 * The 3rd: Interrupt generation is disabled,1: The nINT signal is asserted (driven low) when a new sample is ready in
119 * The 4th: 6th: in typedef enum eDRIVE_MODE_t
120 */
121 uint8_t getMeasurementMode();
122
123 /**
124 * @brief Get the current carbon dioxide concentration
125 * @return current carbon dioxide concentration, unit:ppm
126 */
127 uint16_t getCO2PPM(),
128 /**
129 * @brief Get current TVOC concentration
130 * @return Return current TVOC concentration, unit: ppb
131 */
132 getTVOCPPB();
133 uint16_t readBaseLine();
134 void writeBaseLine(uint16_t baseLine);
135
136protected:
137
138 typedef struct{
139 /*
140 * The CCS811 received an I²C write request addressed to this station but with invalid register address ID
141 */
142 uint8_t sWRITE_REG_INVALID: 1;
143 /*
144 * The CCS811 received an I²C read request to a mailbox ID that is invalid
145 */
146 uint8_t sREAD_REG_INVALID: 1;
147 /*
148 * The CCS811 received an I²C request to write an unsupported mode to MEAS_MODE
149 */
150 uint8_t sMEASMODE_INVALID: 1;
151 /*
152 * The sensor resistance measurement has reached or exceeded the maximum range
153 */
154 uint8_t sMAX_RESISTANCE: 1;
155 /*
156 * The The Heater current in the CCS811 is not in range
157 */
158 uint8_t sHEATER_FAULT: 1;
159 /*
160 * The Heater voltage is not being applied correctly
161 */
162 uint8_t sHEATER_SUPPLY: 1;
163 } __attribute__ ((packed))sError_id;
164
165 typedef struct{
166 /*
167 * ALG_RESULT_DATA crosses one of the thresholds set in the THRESHOLDS register
168 * by more than the hysteresis value (also in the THRESHOLDS register)
169 */
170 uint8_t sINT_THRESH: 1;
171 /*
172 * At the end of each measurement cycle (250ms, 1s, 10s, 60s) a flag is set in the
173 * STATUS register regardless of the setting of this bit.
174 */
175 uint8_t sINT_DATARDY: 1;
176 /*
177 * A new sample is placed in ALG_RESULT_DATA and RAW_DATA registers and the
178 * DATA_READY bit in the STATUS register is set at the defined measurement interval.
179 */
180 uint8_t sDRIVE_MODE: 3;
181 } __attribute__ ((packed))sMeas_mode;
182
183 typedef struct{
184 /*
185 * This bit is cleared by reading ERROR_ID
186 * It is not sufficient to read the ERROR field of ALG_RESULT_DATA and STATUS
187 */
188 uint8_t sERROR: 1;
189 /*
190 * ALG_RESULT_DATA is read on the I²C interface
191 */
192 uint8_t sDATA_READY: 1;
193 uint8_t sAPP_VALID: 1;
194 /*
195 * After issuing a VERIFY command the application software must wait 70ms before
196 * issuing any transactions to CCS811 over the I²C interface
197 */
198 uint8_t sAPP_VERIFY: 1;
199 /*
200 * After issuing the ERASE command the application software must wait 500ms
201 * before issuing any transactions to the CCS811 over the I2C interface.
202 */
203 uint8_t sAPP_ERASE: 1;
204 uint8_t sFW_MODE: 1;
205 } __attribute__ ((packed))sStatus;
206
207
208 void getData(void);
209
210 void writeConfig();
211
212 virtual void writeReg(uint8_t reg, const void* pBuf, size_t size);
213 virtual uint8_t readReg(uint8_t reg, const void* pBuf, size_t size);
214
215
216
217private:
218 TwoWire *_pWire;
219
220 uint16_t eCO2;
221 uint16_t eTVOC;
222};
223
224#endif
diff --git a/src/main/main.ino b/src/main/main.ino
index a435473..e29a174 100644
--- a/src/main/main.ino
+++ b/src/main/main.ino
@@ -1,3 +1,8 @@
1#include <DHT.h>
2#include "ota.h"
3#include <WiFiClient.h>
4#include "CCS811.h"
5
1#define TEMP_SENSOR_PIN 12 6#define TEMP_SENSOR_PIN 12
2#define HUMIDITY_SENSOR_PIN 12 7#define HUMIDITY_SENSOR_PIN 12
3#define FAN_PIN 15 8#define FAN_PIN 15
@@ -10,35 +15,52 @@
10#define HUMIDITY_DESIRED 75 15#define HUMIDITY_DESIRED 75
11#define HUMIDITY_VARIATION 3 // ultrasonic turns on at (75 - 3 = 72) and off 16#define HUMIDITY_VARIATION 3 // ultrasonic turns on at (75 - 3 = 72) and off
12 // at (75 + 3 = 78) 17 // at (75 + 3 = 78)
13
14#include "ota.h"
15
16#include <WiFiClient.h>
17WiFiClient *wific = 0; 18WiFiClient *wific = 0;
18 19
19// Tempature + Humidity Sensor 20// Tempature + Humidity Sensor
20#include <DHT.h>
21#define DHTPIN 12 21#define DHTPIN 12
22#define DHTTYPE DHT11 22#define DHTTYPE DHT11
23DHT dht(DHTPIN, DHTTYPE); 23DHT dht(DHTPIN, DHTTYPE);
24 24
25/*
26 * IIC address default 0x5A, the address becomes 0x5B if the ADDR_SEL is soldered.
27 */
28//CCS811 sensor(&Wire, /*IIC_ADDRESS=*/0x5A);
29CCS811 sensor;
25 30
26void setup () { 31void setup(void)
27 Serial.begin(115200); 32{
28 Serial.println(F("Mushing..."));
29
30 setupWifi((char *) hostname); 33 setupWifi((char *) hostname);
31 setupOTA((char *) hostname); 34 setupOTA((char *) hostname);
32 35
33 dht.begin(); // temp+humidity sensor 36 dht.begin(); // temp+humidity sensor
34 pinMode(PHOTORESISTOR, INPUT); // photo resistor 37 pinMode(PHOTORESISTOR, INPUT); // photo resistor
35 wific = new WiFiClient(); 38 wific = new WiFiClient();
39
40
41 Serial.begin(115200);
42 /*Wait for the chip to be initialized completely, and then exit*/
43 while(sensor.begin() != 0){
44 Serial.println("failed to init chip, please check if the chip connection is fine");
45 delay(1000);
46 }
47 /**
48 * @brief Set measurement cycle
49 * @param cycle:in typedef enum{
50 * eClosed, //Idle (Measurements are disabled in this mode)
51 * eCycle_1s, //Constant power mode, IAQ measurement every second
52 * Ecycle_10s, //Pulse heating mode IAQ measurement every 10 seconds
53 * eCycle_60s, //Low power pulse heating mode IAQ measurement every 60 seconds
54 * eCycle_250ms //Constant power mode, sensor measurement every 250ms
55 * }eCycle_t;
56 */
57 sensor.setMeasCycle(sensor.eCycle_250ms);
36} 58}
37 59
38void log_reading ( float temp_c, float humidity, float heat_index_c, int photons ) { 60void log_reading ( float temp_c, float humidity, float heat_index_c, int photons, uint16_t co2, uint16_t tvoc ) {
39 auto fmt = "T: %.2f H: %.2f HI: %.2f LIGHT: %d\r\n"; 61 auto fmt = "T: %.2f H: %.2f HI: %.2f Light: %d CO2: %d TVOC: %d\r\n";
40 char buf[500]; 62 char buf[500];
41 snprintf(buf, sizeof(buf), fmt, temp_c, humidity, heat_index_c, photons); 63 snprintf(buf, sizeof(buf), fmt, temp_c, humidity, heat_index_c, photons, co2, tvoc);
42 //Serial.printf(fmt, temp_c, humidity, heat_index_c); 64 //Serial.printf(fmt, temp_c, humidity, heat_index_c);
43 Serial.print(buf); 65 Serial.print(buf);
44 if (wific->connected()) { 66 if (wific->connected()) {
@@ -46,46 +68,50 @@ void log_reading ( float temp_c, float humidity, float heat_index_c, int photons
46 } 68 }
47} 69}
48 70
49/*
50Global state variables to hold rolling average humidity, temperature, etc sensor values
51Override state variable is set by network command
52
53Need max and min threshhold values for each sensor too
54
55struct SensorState
56{
57 float rolling_average;
58 float threshold_top;
59 float threshold_bottom;
60 void *top_exceeded_callback();
61 float force_value;
62}
63*/
64
65void loop() { 71void loop() {
66 ArduinoOTA.handle(); 72 uint16_t co2, tvoc;
73
74 delay(1000);
75 if(sensor.checkDataReady() == true){
76 co2 = sensor.getCO2PPM();
77 tvoc = sensor.getTVOCPPB();
78 // Serial.print("CO2: ");
79 // Serial.print(sensor.getCO2PPM());
80 // Serial.print("ppm, TVOC: ");
81 // Serial.print(sensor.getTVOCPPB());
82 // Serial.println("ppb");
83 } else {
84 Serial.println("Data is not ready!");
85 }
86 /*!
87 * @brief Set baseline
88 * @param get from getBaseline.ino
89 */
90 sensor.writeBaseLine(0x847B);
91 //delay cannot be less than measurement cycle
92 //delay(1000);
93
94 ArduinoOTA.handle();
95
96 auto ip = IPAddress(192,168,1,2);
97 auto port = 3141;
98 if (!wific->connected()) {
99 Serial.println("Attempting to connect");
100 wific->connect(ip, port);
101 }
102
103 // Wait a few seconds between measurements.
104
105 float hum = dht.readHumidity();
106 float temp = dht.readTemperature();
107 // Check if any reads failed and exit early (to try again).
108 if (isnan(hum) || isnan(temp) ) {
109 Serial.println(F("Failed to read from DHT sensor!"));
110 return;
111 }
112 float hic = dht.computeHeatIndex(temp, hum, false);
113
114 int photons = analogRead(PHOTORESISTOR);
115 log_reading(temp, hum, hic, photons, co2, tvoc);
67 116
68
69 auto ip = IPAddress(192,168,1,2);
70 auto port = 3141;
71 if (!wific->connected()) {
72 Serial.println("Attempting to connect");
73 wific->connect(ip, port);
74 }
75
76 // Wait a few seconds between measurements.
77 delay(2000);
78
79 float h = dht.readHumidity();
80 float t = dht.readTemperature();
81 // Check if any reads failed and exit early (to try again).
82 if (isnan(h) || isnan(t) ) {
83 Serial.println(F("Failed to read from DHT sensor!"));
84 return;
85 }
86 float hic = dht.computeHeatIndex(t, h, false);
87
88 int photons = analogRead(PHOTORESISTOR);
89 log_reading(t, h, hic, photons);
90} 117}
91