Here is what I am trying to achieve. Get PH Value from water into a database along with all of my other sensors.
I have this ph sensor > https://www.dfrobot.com/index.php?route ... ct_id=1110 connected to an TKLCD(Arduino Leonardo with LCD attached) The sensor is connected to A0 analog pin and then connected to ESP8266-12E through i2c. The ESP8266 is running espeasy and I am trying to get the PH values into MQTT with the Pro Mini Extender.
I can get accurate PH readings printed into the serial monitor of the arduino IDE and the LCD but through the ESPeasy logs I get '0.00'. Basicially, if some kind soul could take a look at my code and tell me what im doing wrong. What in this code tells ESPeasy to take the PHValue.
Here is the DFRobot sample code for the PH Probe
Code: Select all
/*
# This sample code is used to test the pH meter V1.1.
# Editor : YouYou
# Date : 2014.06.23
# Ver : 1.1
# Product: analog pH meter V1.1
# SKU : SEN0161
*/
#define SensorPin A2 //pH meter Analog output to Arduino Analog Input 2
#define Offset 0.00 //deviation compensate
#define LED 13
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth 40 //times of collection
int pHArray[ArrayLenth]; //Store the average value of the sensor feedback
int pHArrayIndex=0;
void setup(void)
{
pinMode(LED,OUTPUT);
Serial.begin(9600);
Serial.println("pH meter experiment!"); //Test the serial monitor
}
void loop(void)
{
static unsigned long samplingTime = millis();
static unsigned long printTime = millis();
static float pHValue,voltage;
if(millis()-samplingTime > samplingInterval)
{
pHArray[pHArrayIndex++]=analogRead(SensorPin);
if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
pHValue = 3.5*voltage+Offset;
samplingTime=millis();
}
if(millis() - printTime > printInterval) //Every 800 milliseconds, print a numerical, convert the state of the LED indicator
{
Serial.print("Voltage:");
Serial.print(voltage,2);
Serial.print(" pH value: ");
Serial.println(pHValue,2);
digitalWrite(LED,digitalRead(LED)^1);
printTime=millis();
}
}
double avergearray(int* arr, int number){
int i;
int max,min;
double avg;
long amount=0;
if(number<=0){
Serial.println("Error number for the array to avraging!/n");
return 0;
}
if(number<5){ //less than 5, calculated directly statistics
for(i=0;i<number;i++){
amount+=arr[i];
}
avg = amount/number;
return avg;
}else{
if(arr[0]<arr[1]){
min = arr[0];max=arr[1];
}
else{
min=arr[1];max=arr[0];
}
for(i=2;i<number;i++){
if(arr[i]<min){
amount+=min; //arr<min
min=arr[i];
}else {
if(arr[i]>max){
amount+=max; //arr>max
max=arr[i];
}else{
amount+=arr[i]; //min<=arr<=max
}
}//if
}//for
avg = (double)amount/(number-2);
}//if
return avg;
}
Here is the code I hacked together to try and get the pHValue to show up in the espeasy logs. I gutted much of the proMiniExtender code down to just what sends data over(or at least I think I did) just to try and figure out why I cant get anything but 0.00
Code: Select all
#include <Wire.h>
#define I2C_MSG_IN_SIZE 4
#define I2C_MSG_OUT_SIZE 4
#define CMD_ANALOG_READ 4
#define SensorPin A0 //pH meter Analog output to Arduino Analog Input 2
#define Offset 0.00 //deviation compensate
#define LED 13
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth 40
//#define SensorPin A2 //pH meter Analog output to Arduino Analog Input 2
//times of collection
volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE];
int pHValue;
int pHArray[ArrayLenth]; //Store the average value of the sensor feedback
int pHArrayIndex=0;
void setup(void)
{
Wire.begin(0x7f);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
}
int valueRead;
void loop(void)
{
static unsigned long samplingTime = millis();
static unsigned long printTime = millis();
static float pHValue,voltage;
if(millis()-samplingTime > samplingInterval)
{
pHArray[pHArrayIndex++]=analogRead(SensorPin);
if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
pHValue = (3.5*voltage+Offset)*1000; /////////// // conversion of float Ampere into integer milliAmpere needed for I2C communication
samplingTime=millis();
}
if(millis() - printTime > printInterval) //Every 800 milliseconds, print a numerical, convert the state of the LED indicator
{
Serial.print("Voltage:");
Serial.print(voltage,2);
Serial.print(" pH value: ");
Serial.println(pHValue,2);
digitalWrite(LED,digitalRead(LED)^1);
printTime=millis();
}
}
double avergearray(int* arr, int number){
int i;
int max,min;
double avg;
long amount=0;
if(number<=0){
Serial.println("Error number for the array to avraging!/n");
return 0;
}
if(number<5){ //less than 5, calculated directly statistics
for(i=0;i<number;i++){
amount+=arr[i];
}
avg = amount/number;
return avg;
}else{
if(arr[0]<arr[1]){
min = arr[0];max=arr[1];
}
else{
min=arr[1];max=arr[0];
}
for(i=2;i<number;i++){
if(arr[i]<min){
amount+=min; //arr<min
min=arr[i];
}else {
if(arr[i]>max){
amount+=max; //arr>max
max=arr[i];
}else{
amount+=arr[i]; //min<=arr<=max
}
}//if
}//for
avg = (double)amount/(number-2);
}//if
return avg;
}
void receiveEvent(int count)
{
if (count == I2C_MSG_IN_SIZE)
{
byte cmd = Wire.read();
byte port = Wire.read();
int value = Wire.read();
value += Wire.read()*256;
switch(cmd)
{
case CMD_ANALOG_READ:
clearSendBuffer();
//if (port <= 4) valueRead = analogRead(port); /////////change this line:[ int valueRead = analogRead(port); ] into: int valueRead = prepared_temperature;
if (port == 100) valueRead = pHValue;
sendBuffer[0] = valueRead & 0xff;
sendBuffer[1] = valueRead >> 8;
break;
}
}
}
void clearSendBuffer()
{
for(byte x=0; x < sizeof(sendBuffer); x++)
sendBuffer[x]=0;
}
void requestEvent()
{
Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer));
}
Here is my version of the code that works but alas, these are not PH Values..costo wrote:In the sketch for adc_zero = 514 was for my case the best value. Theoretically it should be 511. You should experiment with this value to get the lowest reading without current. It will never be zero because the ACS712 has some noise from itself. About 0.12 Ampere was the lowest zero reading I got.Code: Select all
/********************************************************************************************************************\ * Arduino project "ESP Easy" Copyright www.esp8266.nu * * 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 received a copy of the GNU General Public License along with this program in file 'License.txt'. * * IDE download : https://www.arduino.cc/en/Main/Software * ESP8266 Package : https://github.com/esp8266/Arduino * * Source Code : https://sourceforge.net/projects/espeasy/ * Support : http://www.esp8266.nu * Discussion : http://www.esp8266.nu/forum/ * * Additional information about licensing can be found at : http://www.gnu.org/licenses \******************************************************************************************************************/ // This file is to be loaded onto an Arduino Pro Mini so it will act as a simple IO extender to the ESP module. // Communication between ESP and Arduino is using the I2C bus, so only two wires needed. // It is possible to run the Pro Mini on 3V3, although the 16MHz versions do not officially support this at 16MHzl // By working on 3.3volt you can skip levelconverters on I2C, but no guarantee that it will work stable. // Arduino Mini Pro uses A4 and A5 for I2C bus. ESP I2C can be configured but they are on GPIO-4 and GPIO-5 by default. #include <Wire.h> #define I2C_MSG_IN_SIZE 4 #define I2C_MSG_OUT_SIZE 4 #define CMD_DIGITAL_WRITE 1 #define CMD_DIGITAL_READ 2 #define CMD_ANALOG_WRITE 3 #define CMD_ANALOG_READ 4 volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE]; int ESPrms; // value to be sent over I2C to ESP void setup() { Wire.begin(0x7f); Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); } /* ****************************************************************************************************************** This part in the loop found here: [url] https://forum.arduino.cc/index.php?topic=179541.0 [/url] tnx to dc42 constant 75.7576 depends on the sensitivity of the ACS712 module Sensitivity Min<Typ<Max mV/A for 30A: 64< 66< 68 mV/A > constant = 5/.066 = 75.76 for 10A: 96<100<104 mV/A > constant = 5/.1 = 50.00 for 5A: 180<185<190 mV/A > constant = 5/.185 = 27.03 */ const int currentPin = A7; // ADC pin used for ACS712 const unsigned long sampleTime = 100000UL; // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains const unsigned long numSamples = 250L; // number of samples 400 microsecond each const unsigned long sampleInterval = sampleTime/numSamples; // sampling interval, must be longer than then ADC conversion time int adc_zero = 514; // relative zero of the ACS712 for me 514 was best. 511 int valueRead; // value read on ADC void loop() { unsigned long currentAcc = 0; unsigned int count = 0; unsigned long prevMicros = micros() - sampleInterval ; while (count < numSamples) { if (micros() - prevMicros >= sampleInterval) { long adc_raw = analogRead(currentPin) - adc_zero; currentAcc += (unsigned long)(adc_raw * adc_raw); ++count; prevMicros += sampleInterval; } } float rms = sqrt((float)currentAcc/(float)numSamples) * (27.03 / 1024.0); // see note above for this 27.03 value ESPrms = 1000*rms; // conversion of float Ampere into integer milliAmpere needed for I2C communication } /* ******************************************************************************************************************* void receiveEvent(int count) { if (count == I2C_MSG_IN_SIZE) { byte cmd = Wire.read(); byte port = Wire.read(); int value = Wire.read(); value += Wire.read()*256; switch(cmd) { case CMD_DIGITAL_WRITE: pinMode(port,OUTPUT); digitalWrite(port,value); break; case CMD_DIGITAL_READ: pinMode(port,INPUT_PULLUP); clearSendBuffer(); sendBuffer[0] = digitalRead(port); break; case CMD_ANALOG_WRITE: analogWrite(port,value); break; case CMD_ANALOG_READ: clearSendBuffer(); if (port <= 4) valueRead = analogRead(port); // port <=4 to read analog value A0,A1,A2,A3 - A4 & A5 are I2C if (port == 100) valueRead = ESPrms; // port is any number >4 up to 255 sendBuffer[0] = valueRead & 0xff; sendBuffer[1] = valueRead >> 8; break; } } } void clearSendBuffer() { for(byte x=0; x < sizeof(sendBuffer); x++) sendBuffer[x]=0; } void requestEvent() { Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer)); }
In the device on ESPEasy:
Device: ProMini Extender
Name: Ampere
IDX: some value needed here, ID number from the server
Port: 100 (port number choosen in the sketch to couple with rms_value)
Port Type: Analog
Formula Value: %value%/1000 (to convert milliAmp to Ampere
Code: Select all
/********************************************************************************************************************\
* Arduino project "ESP Easy" Copyright www.esp8266.nu
*
* 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 received a copy of the GNU General Public License along with this program in file 'License.txt'.
*
* IDE download : https://www.arduino.cc/en/Main/Software
* ESP8266 Package : https://github.com/esp8266/Arduino
*
* Source Code : https://sourceforge.net/projects/espeasy/
* Support : http://www.esp8266.nu
* Discussion : http://www.esp8266.nu/forum/
*
* Additional information about licensing can be found at : http://www.gnu.org/licenses
\******************************************************************************************************************/
// This file is to be loaded onto an Arduino Pro Mini so it will act as a simple IO extender to the ESP module.
// Communication between ESP and Arduino is using the I2C bus, so only two wires needed.
// It is possible to run the Pro Mini on 3V3, although the 16MHz versions do not officially support this at 16MHzl
// By working on 3.3volt you can skip levelconverters on I2C, but no guarantee that it will work stable.
// Arduino Mini Pro uses A4 and A5 for I2C bus. ESP I2C can be configured but they are on GPIO-4 and GPIO-5 by default.
#include <Wire.h>
#define I2C_MSG_IN_SIZE 4
#define I2C_MSG_OUT_SIZE 4
#define CMD_DIGITAL_WRITE 1
#define CMD_DIGITAL_READ 2
#define CMD_ANALOG_WRITE 3
#define CMD_ANALOG_READ 4
volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE];
int ESPrms; // value to be sent over I2C to ESP
//int rms; // value to be sent over I2C to ESP
void setup()
{
Wire.begin(0x7f);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
}
/* ******************************************************************************************************************
This part in the loop found here: [url] https://forum.arduino.cc/index.php?topic=179541.0 [/url] tnx to dc42
constant 75.7576 depends on the sensitivity of the ACS712 module
Sensitivity Min<Typ<Max mV/A
for 30A: 64< 66< 68 mV/A > constant = 5/.066 = 75.76
for 10A: 96<100<104 mV/A > constant = 5/.1 = 50.00
for 5A: 180<185<190 mV/A > constant = 5/.185 = 27.03
*/
const int currentPin = A0; // ADC pin used for ACS712
const unsigned long sampleTime = 100000UL; // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains
const unsigned long numSamples = 10000; // number of samples 400 microsecond each
const unsigned long sampleInterval = sampleTime/numSamples; // sampling interval, must be longer than then ADC conversion time
int adc_zero = 514; // relative zero of the ACS712 for me 514 was best. 511
int valueRead; // value read on ADC
void loop()
{
unsigned long currentAcc = 0;
unsigned int count = 0;
unsigned long prevMicros = micros() - sampleInterval ;
while (count < numSamples)
{
if (micros() - prevMicros >= sampleInterval)
{
long adc_raw = analogRead(currentPin) - adc_zero;
currentAcc += (unsigned long)(adc_raw * adc_raw);
++count;
prevMicros += sampleInterval;
}
}
float rms = sqrt((float)currentAcc/(float)numSamples) * (27.03 / 1024.0); // see note above for this 27.03 value
ESPrms = 2000*rms; // conversion of float Ampere into integer milliAmpere needed for I2C communication
}
//* *******************************************************************************************************************
void receiveEvent(int count)
{
if (count == I2C_MSG_IN_SIZE)
{
byte cmd = Wire.read();
byte port = Wire.read();
int value = Wire.read();
value += Wire.read()*256;
switch(cmd)
{
case CMD_ANALOG_READ:
clearSendBuffer();
//if (port <= 0) valueRead = analogRead(port); // port <=4 to read analog value A0,A1,A2,A3 - A4 & A5 are I2C
if (port == 100) valueRead = ESPrms; // port is any number >4 up to 255
//sendBuffer[0] = valueRead & 0xff;
sendBuffer[1] = valueRead >> 8;
break;
}
}
}
void clearSendBuffer()
{
for(byte x=0; x < sizeof(sendBuffer); x++)
sendBuffer[x]=0;
}
void requestEvent()
{
Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer));
}