mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-26 22:22:16 +03:00
220 lines
8.7 KiB
C++
220 lines
8.7 KiB
C++
/*
|
|
* The MySensors Arduino library handles the wireless radio link and protocol
|
|
* between your home built sensors/actuators and HA controller of choice.
|
|
* The sensors forms a self healing radio network with optional repeaters. Each
|
|
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
|
* network topology allowing messages to be routed to nodes.
|
|
*
|
|
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
|
* Copyright (C) 2013-2019 Sensnology AB
|
|
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
|
|
*
|
|
* Documentation: http://www.mysensors.org
|
|
* Support Forum: http://forum.mysensors.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* version 2 as published by the Free Software Foundation.
|
|
*
|
|
*******************************
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Connect the MQ2 sensor as follows :
|
|
*
|
|
* A H A >>> 5V
|
|
* B >>> A0
|
|
* H >>> GND
|
|
* B >>> 10K ohm >>> GND
|
|
*
|
|
* Contribution: epierre
|
|
* Based on http://sandboxelectronics.com/?p=165
|
|
* License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
|
|
* Modified by HEK to work in 1.4
|
|
*
|
|
*/
|
|
|
|
// Enable debug prints to serial monitor
|
|
#define MY_DEBUG
|
|
|
|
// Enable and select radio type attached
|
|
#define MY_RADIO_RF24
|
|
//#define MY_RADIO_NRF5_ESB
|
|
//#define MY_RADIO_RFM69
|
|
//#define MY_RADIO_RFM95
|
|
|
|
#include <MySensors.h>
|
|
|
|
#define CHILD_ID_MQ 0
|
|
/************************Hardware Related Macros************************************/
|
|
#define MQ_SENSOR_ANALOG_PIN (0) //define which analog input channel you are going to use
|
|
#define RL_VALUE (5) //define the load resistance on the board, in kilo ohms
|
|
#define RO_CLEAN_AIR_FACTOR (9.83) //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
|
|
//which is derived from the chart in datasheet
|
|
/***********************Software Related Macros************************************/
|
|
#define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase
|
|
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interval(in milliseconds) between each samples in the
|
|
//calibration phase
|
|
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
|
|
#define READ_SAMPLE_TIMES (5) //define the time interval(in milliseconds) between each samples in
|
|
//normal operation
|
|
/**********************Application Related Macros**********************************/
|
|
#define GAS_LPG (0)
|
|
#define GAS_CO (1)
|
|
#define GAS_SMOKE (2)
|
|
/*****************************Globals***********************************************/
|
|
uint32_t SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
|
//VARIABLES
|
|
float Ro = 10000.0; // this has to be tuned 10K Ohm
|
|
int val = 0; // variable to store the value coming from the sensor
|
|
uint16_t lastMQ = 0;
|
|
float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve.
|
|
//with these two points, a line is formed which is "approximately equivalent"
|
|
//to the original curve.
|
|
//data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
|
|
float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve.
|
|
//with these two points, a line is formed which is "approximately equivalent"
|
|
//to the original curve.
|
|
//data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15)
|
|
float SmokeCurve[3] = {2.3,0.53,-0.44}; //two points are taken from the curve.
|
|
//with these two points, a line is formed which is "approximately equivalent"
|
|
//to the original curve.
|
|
//data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22)
|
|
|
|
|
|
MyMessage msg(CHILD_ID_MQ, V_LEVEL);
|
|
|
|
void setup()
|
|
{
|
|
Ro = MQCalibration(
|
|
MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air
|
|
}
|
|
|
|
void presentation()
|
|
{
|
|
// Send the sketch version information to the gateway and Controller
|
|
sendSketchInfo("Air Quality Sensor", "1.0");
|
|
|
|
// Register all sensors to gateway (they will be created as child devices)
|
|
present(CHILD_ID_MQ, S_AIR_QUALITY);
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO);
|
|
Serial.println(val);
|
|
|
|
Serial.print("LPG:");
|
|
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_LPG) );
|
|
Serial.print( "ppm" );
|
|
Serial.print(" ");
|
|
Serial.print("CO:");
|
|
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO) );
|
|
Serial.print( "ppm" );
|
|
Serial.print(" ");
|
|
Serial.print("SMOKE:");
|
|
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_SMOKE) );
|
|
Serial.print( "ppm" );
|
|
Serial.print("\n");
|
|
|
|
if (valMQ != lastMQ) {
|
|
send(msg.set((int16_t)ceil(valMQ)));
|
|
lastMQ = ceil(valMQ);
|
|
}
|
|
|
|
sleep(SLEEP_TIME); //sleep for: sleepTime
|
|
}
|
|
|
|
/****************** MQResistanceCalculation ****************************************
|
|
Input: raw_adc - raw value read from adc, which represents the voltage
|
|
Output: the calculated sensor resistance
|
|
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage
|
|
across the load resistor and its resistance, the resistance of the sensor
|
|
could be derived.
|
|
************************************************************************************/
|
|
float MQResistanceCalculation(int raw_adc)
|
|
{
|
|
return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
|
|
}
|
|
|
|
/***************************** MQCalibration ****************************************
|
|
Input: mq_pin - analog channel
|
|
Output: Ro of the sensor
|
|
Remarks: This function assumes that the sensor is in clean air. It use
|
|
MQResistanceCalculation to calculates the sensor resistance in clean air
|
|
and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about
|
|
10, which differs slightly between different sensors.
|
|
************************************************************************************/
|
|
float MQCalibration(int mq_pin)
|
|
{
|
|
int i;
|
|
float inVal=0;
|
|
|
|
for (i=0; i<CALIBARAION_SAMPLE_TIMES; i++) { //take multiple samples
|
|
inVal += MQResistanceCalculation(analogRead(mq_pin));
|
|
delay(CALIBRATION_SAMPLE_INTERVAL);
|
|
}
|
|
inVal = inVal/CALIBARAION_SAMPLE_TIMES; //calculate the average value
|
|
|
|
inVal = inVal/RO_CLEAN_AIR_FACTOR; //divided by RO_CLEAN_AIR_FACTOR yields the Ro
|
|
//according to the chart in the datasheet
|
|
|
|
return inVal;
|
|
}
|
|
/***************************** MQRead *********************************************
|
|
Input: mq_pin - analog channel
|
|
Output: Rs of the sensor
|
|
Remarks: This function use MQResistanceCalculation to calculate the sensor resistance (Rs).
|
|
The Rs changes as the sensor is in the different concentration of the target
|
|
gas. The sample times and the time interval between samples could be configured
|
|
by changing the definition of the macros.
|
|
************************************************************************************/
|
|
float MQRead(int mq_pin)
|
|
{
|
|
int i;
|
|
float rs=0;
|
|
|
|
for (i=0; i<READ_SAMPLE_TIMES; i++) {
|
|
rs += MQResistanceCalculation(analogRead(mq_pin));
|
|
delay(READ_SAMPLE_INTERVAL);
|
|
}
|
|
|
|
rs = rs/READ_SAMPLE_TIMES;
|
|
|
|
return rs;
|
|
}
|
|
|
|
/***************************** MQGetGasPercentage **********************************
|
|
Input: rs_ro_ratio - Rs divided by Ro
|
|
gas_id - target gas type
|
|
Output: ppm of the target gas
|
|
Remarks: This function passes different curves to the MQGetPercentage function which
|
|
calculates the ppm (parts per million) of the target gas.
|
|
************************************************************************************/
|
|
int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
|
|
{
|
|
if ( gas_id == GAS_LPG ) {
|
|
return MQGetPercentage(rs_ro_ratio,LPGCurve);
|
|
} else if ( gas_id == GAS_CO ) {
|
|
return MQGetPercentage(rs_ro_ratio,COCurve);
|
|
} else if ( gas_id == GAS_SMOKE ) {
|
|
return MQGetPercentage(rs_ro_ratio,SmokeCurve);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************** MQGetPercentage **********************************
|
|
Input: rs_ro_ratio - Rs divided by Ro
|
|
pcurve - pointer to the curve of the target gas
|
|
Output: ppm of the target gas
|
|
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
|
|
of the line could be derived if y(rs_ro_ratio) is provided. As it is a
|
|
logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
|
|
value.
|
|
************************************************************************************/
|
|
int MQGetPercentage(float rs_ro_ratio, float *pcurve)
|
|
{
|
|
return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
|
|
}
|