Hello, I think I need some help with my ESP32 based project
Project name: ESP32 based cat feeder with current sensor for prevent kibble from stucking
Setup: this is pretty straightforward
220 to 5v Converter
5v Separately going into Esp32 Vin and to 5V to 6V step up converter, then into current sensor, the into an L298 motor drivet that activates a DC motor that turns the auger when the cat pushes a button. If the current signal goes under the threshold, then the motor stops, makes a half turn backwards and then goes back to its original spinning verse
The motor driver is controlled using two esp32 pins and reads AC signal to through ADC from the current sensor
My first sketch is does not use any MQTT nore wifi and runs just smooth:
This is the code
#define SIG 4 // YELLOW
#define IN2 22
#define IN1 21
#define BUT 2
float segnale=0;
int buttonState = 0;
int stall = 0;
void setup() {
Serial.begin(115200);
pinMode(SIG,INPUT);
pinMode(BUT,INPUT_PULLDOWN);
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
}
void setMotor(int direz){
if(direz == 1){
digitalWrite(IN1,HIGH);
digitalWrite(IN2,LOW);
//Serial.println(posi);
}
else if(direz == 2){
digitalWrite(IN1,LOW);
digitalWrite(IN2,HIGH);
readVoltage();
//Serial.println(posi);
}
else{
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW);
}
delay(10);
}
void readVoltage()
{
float sig = 0;
for (int i=0; i<20;i++) {
sig+= analogRead(SIG);
delay(10);
}
sig= sig/20;
Serial.println (sig);
segnale=sig;
//float volt= sig-2826;//questo è il delta su 2826 che è il segnale a riposo
//a tensione spenta il segnale è di 3042. ESP ha 4096 campioni sul piedino e misura fino a 3.3 V.
//adesso lo trasformo veramente in millivolt. 3300/4096 sono i millivolt di ogni step sul piedino
//volt=volt*0.805;//questi sono i veri mV di delta su 2.5 V di base
//float mamp= volt/185; //ogni 185 mV è 1 Amp
Serial.println("sig: ");
Serial.print(sig);
}
void erogazione()
//quando uso setMotor2, read voltage fa 20 campioni da 10 ms perciò 200 ms, perciò se non ho problemi faccio 30 volte un ciclo da 200 ms cioè 6 secondi
{
stall = 0;
for (int k=0; k<30;k++) {
setMotor(2);
if(segnale<2925){
setMotor(3);
delay(1500);
setMotor(1);
delay(2000);
setMotor(3);
delay(1000);
stall=stall+1;
}
Serial.println("k: ");
Serial.print(k);
}
setMotor(3);
Serial.println("stall: ");
Serial.println(stall);
}
void loop() {
buttonState = digitalRead(BUT);
if (buttonState == HIGH) {
erogazione();
}
}
once i got this working, I was trying to add the use of MQTT protocol in order to publish to my Hass instance if and how many times the feeder got stuck by the kibble.
It runs perfectly right after boot and reset, but then after the first round, it only runs the anti stucking algorithm as the signal from the sensor is constantly displaying 0
#define SIG 4 // YELLOW
#define IN2 22
#define IN1 21
#define BUT 2
int segnale=0;
int buttonState = 0;
int stall = 0;
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>
// Replace the next variables with your SSID/Password combination
const char* ssid = "xxxxxx";
const char* password = "xxxxxxx";
// Add your MQTT Broker IP address, example:
//const char* mqtt_server = "xxxxx";
const char* mqtt_server ="xxxx";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
void setup() {
Serial.begin(115200);
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
pinMode(SIG,INPUT);
pinMode(BUT,INPUT_PULLDOWN);
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
}
void callback(char* topic, byte* message, unsigned int length) {
String messageTemp;
for (int i = 0; i < length; i++) {
messageTemp += (char)message[i];
}
}
void mqtt(){
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);}
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 5000) {
lastMsg = now;
// scrivo i dati in uscita
char sigout[10];
dtostrf(segnale, 4, 0, sigout);
char stallout [2];
dtostrf(stall, 2, 0, stallout);
//String totout = strcat (sigout,stallout);
//client.publish("test1", sigout);
delay (1000);
client.publish("test1", stallout);
}
client.disconnect();
WiFi.disconnect();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("xxxx",xxmymqttuserxx,xxmymqttpassxx)) {
Serial.println("connected");
// Subscribe
client.subscribe("test1");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setMotor(int direz){
if(direz == 1){
digitalWrite(IN1,HIGH);
digitalWrite(IN2,LOW);
//Serial.println(posi);
}
else if(direz == 2){
digitalWrite(IN1,LOW);
digitalWrite(IN2,HIGH);
readVoltage();
//Serial.println(posi);
}
else{
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW);
}
delay(10);
}
void readVoltage()
{
float sig = 0;
for (int i=0; i<20;i++) {
sig+= analogRead(SIG);
delay(10);
}
sig= sig/20;
Serial.println (sig);
segnale=abs(sig);
//float volt= sig-2826;//questo è il delta su 2826 che è il segnale a riposo
//a tensione spenta il segnale è di 3042. ESP ha 4096 campioni sul piedino e misura fino a 3.3 V.
//adesso lo trasformo veramente in millivolt. 3300/4096 sono i millivolt di ogni step sul piedino
//volt=volt*0.805;//questi sono i veri mV di delta su 2.5 V di base
//float mamp= volt/185; //ogni 185 mV è 1 Amp
Serial.println("sig: ");
Serial.print(sig);
}
void erogazione()
//quando uso setMotor2, read voltage fa 20 campioni da 10 ms perciò 200 ms, perciò se non ho problemi faccio 30 volte un ciclo da 200 ms cioè 6 secondi
{
stall = 0;
for (int k=0; k<30;k++) {
setMotor(2);
//era 2925
if(segnale<2425){
setMotor(3);
delay(1500);
setMotor(1);
delay(2000);
setMotor(3);
delay(1000);
stall=stall+1;
}
Serial.println("k: ");
Serial.print(k);
}
setMotor(3);
Serial.println("stall: ");
Serial.println(stall);
}
void loop() {
buttonState = digitalRead(BUT);
if (buttonState == HIGH) {
erogazione();
mqtt();
}
}
I was wondering wheter the wifi begin ->mqtt connec-> publish-> mqtt disconnec-> wifi disconnect
routine can somehow affect the signal of the current sensor dropping it to zero, but honestly I have no clue.
Any help would be very much appreciated as I am quite stuck.
The mqtt() function needs some work. If you are expecting MQTT payloads then it would be best to keep the WiFi and MQTT connection open and run client.loop() on a regular basis.
Here is some good working MQTT code that reads sensors and on a periodic basis sends the data to the MQTT Broker. Perhaps it may serve as a model.
/*
Chappie Weather upgrade/addition
process wind speed direction and rain fall.
*/
#include "esp32/ulp.h"
//#include "ulptool.h"
#include "driver/rtc_io.h"
#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include "driver/pcnt.h"
#include <driver/adc.h>
#include <SimpleKalmanFilter.h>
#include <ESP32Time.h>
////
ESP32Time rtc;
WiFiClient wifiClient;
PubSubClient MQTTclient(mqtt_server, mqtt_port, wifiClient);
////
float CalculatedVoltage = 0.0f;
float kph = 0.0f;
float rain = 0.0f;
/*
PCNT PCNT_UNIT_0, PCNT_CHANNEL_0 GPIO_NUM_15 = pulse input pin
PCNT PCNT_UNIT_1, PCNT_CHANNEL_0 GPIO_NUM_4 = pulse input pin
*/
pcnt_unit_t pcnt_unit00 = PCNT_UNIT_0; //pcnt unit 0 channel 0
pcnt_unit_t pcnt_unit10 = PCNT_UNIT_1; //pcnt unit 1 channel 0
//
//
hw_timer_t * timer = NULL;
//
#define evtAnemometer ( 1 << 0 )
#define evtRainFall ( 1 << 1 )
#define evtParseMQTT ( 1 << 2 )
EventGroupHandle_t eg;
#define OneMinuteGroup ( evtAnemometer | evtRainFall )
////
QueueHandle_t xQ_Message; // payload and topic queue of MQTT payload and topic
const int payloadSize = 100;
struct stu_message
{
char payload [payloadSize] = {'\0'};
String topic ;
} x_message;
////
SemaphoreHandle_t sema_MQTT_KeepAlive;
SemaphoreHandle_t sema_mqttOK;
SemaphoreHandle_t sema_CalculatedVoltage;
////
int mqttOK = 0; // stores a count value that is used to cause an esp reset
volatile bool TimeSet = false;
////
/*
A single subject has been subscribed to, the mqtt broker sends out "OK" messages if the client receives an OK message the mqttOK value is set back to zero.
*/
////
void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
memset( x_message.payload, '\0', payloadSize ); // clear payload char buffer
x_message.topic = ""; //clear topic string buffer
x_message.topic = topic; //store new topic
int i = 0; // extract payload
for ( i; i < length; i++)
{
x_message.payload[i] = ((char)payload[i]);
}
x_message.payload[i] = '\0';
xQueueOverwrite( xQ_Message, (void *) &x_message );// send data to queue
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
// interrupt service routine for WiFi events put into IRAM
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_STA_CONNECTED:
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
log_i("Disconnected from WiFi access point");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
log_i("WiFi client disconnected");
break;
default: break;
}
} // void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
////
void IRAM_ATTR onTimer()
{
BaseType_t xHigherPriorityTaskWoken;
xEventGroupSetBitsFromISR(eg, OneMinuteGroup, &xHigherPriorityTaskWoken);
} // void IRAM_ATTR onTimer()
////
void setup()
{
eg = xEventGroupCreate(); // get an event group handle
x_message.topic.reserve(100);
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);// using GPIO 34 wind direction
adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11);// using GPIO 39 current
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);// using GPIO 36 battery volts
// hardware timer 4 set for one minute alarm
timer = timerBegin( 3, 80, true );
timerAttachInterrupt( timer, &onTimer, true );
timerAlarmWrite(timer, 60000000, true);
timerAlarmEnable(timer);
/* Initialize PCNT's counter */
int PCNT_H_LIM_VAL = 3000;
int PCNT_L_LIM_VAL = -10;
// 1st PCNT counter
pcnt_config_t pcnt_config = {};
pcnt_config.pulse_gpio_num = GPIO_NUM_15;// Set PCNT input signal and control GPIOs
pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
pcnt_config.channel = PCNT_CHANNEL_0;
pcnt_config.unit = PCNT_UNIT_0;
// What to do on the positive / negative edge of pulse input?
pcnt_config.pos_mode = PCNT_COUNT_INC; // Count up on the positive edge
pcnt_config.neg_mode = PCNT_COUNT_DIS; // Count down disable
// What to do when control input is low or high?
pcnt_config.lctrl_mode = PCNT_MODE_KEEP; // Keep the primary counter mode if low
pcnt_config.hctrl_mode = PCNT_MODE_KEEP; // Keep the primary counter mode if high
// Set the maximum and minimum limit values to watch
pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
pcnt_unit_config(&pcnt_config); // Initialize PCNT unit
pcnt_set_filter_value( PCNT_UNIT_0, 1); //Configure and enable the input filter
pcnt_filter_enable( PCNT_UNIT_0 );
pcnt_counter_pause( PCNT_UNIT_0 );
pcnt_counter_clear( PCNT_UNIT_0 );
pcnt_counter_resume( PCNT_UNIT_0); // start the show
// setup 2nd PCNT
pcnt_config = {};
pcnt_config.pulse_gpio_num = GPIO_NUM_4;
pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
pcnt_config.channel = PCNT_CHANNEL_0;
pcnt_config.unit = PCNT_UNIT_1;
pcnt_config.pos_mode = PCNT_COUNT_INC;
pcnt_config.neg_mode = PCNT_COUNT_DIS;
pcnt_config.lctrl_mode = PCNT_MODE_KEEP;
pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
pcnt_unit_config(&pcnt_config);
//pcnt_set_filter_value( PCNT_UNIT_1, 1 );
//pcnt_filter_enable ( PCNT_UNIT_1 );
pcnt_counter_pause ( PCNT_UNIT_1 );
pcnt_counter_clear ( PCNT_UNIT_1 );
pcnt_counter_resume ( PCNT_UNIT_1 );
//
xQ_Message = xQueueCreate( 1, sizeof(stu_message) );
//
sema_CalculatedVoltage = xSemaphoreCreateBinary();
xSemaphoreGive( sema_CalculatedVoltage );
sema_mqttOK = xSemaphoreCreateBinary();
xSemaphoreGive( sema_mqttOK );
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
///
xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 15000, NULL, 5, NULL, 1 );
xTaskCreatePinnedToCore( fparseMQTT, "fparseMQTT", 10000, NULL, 5, NULL, 1 ); // assign all to core 1, WiFi in use.
xTaskCreatePinnedToCore( fReadBattery, "fReadBattery", 4000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fReadCurrent, "fReadCurrent", 4000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fWindDirection, "fWindDirection", 10000, NULL, 4, NULL, 1 );
xTaskCreatePinnedToCore( fAnemometer, "fAnemometer", 10000, NULL, 4, NULL, 1 );
xTaskCreatePinnedToCore( fRainFall, "fRainFall", 10000, NULL, 4, NULL, 1 );
xTaskCreatePinnedToCore( fmqttWatchDog, "fmqttWatchDog", 3000, NULL, 3, NULL, 1 ); // assign all to core 1
} //void setup()
static void init_ulp_program()
{
}
////
void fWindDirection( void *pvParameters )
// read the wind direction sensor, return heading in degrees
{
float adcValue = 0.0f;
uint64_t TimePastKalman = esp_timer_get_time();
SimpleKalmanFilter KF_ADC( 1.0f, 1.0f, .01f );
float high = 0.0f;
float low = 2000.0f;
float ADscale = 3.3f / 4096.0f;
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 100; //delay for mS
int count = 0;
String windDirection;
windDirection.reserve(20);
String MQTTinfo = "";
MQTTinfo.reserve( 150 );
while ( !MQTTclient.connected() )
{
vTaskDelay( 250 );
}
for (;;)
{
windDirection = "";
adcValue = float( adc1_get_raw(ADC1_CHANNEL_6) ); //take a raw ADC reading
KF_ADC.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
adcValue = KF_ADC.updateEstimate( adcValue ); // apply simple Kalman filter
TimePastKalman = esp_timer_get_time(); // time of update complete
adcValue = adcValue * ADscale;
if ( (adcValue >= 0.0f) & (adcValue <= .25f ) )
{
// log_i( " n" );
windDirection.concat( "N" );
}
if ( (adcValue > .25f) & (adcValue <= .6f ) )
{
// log_i( " e" );
windDirection.concat( "E" );
}
if ( (adcValue > 2.0f) & ( adcValue < 3.3f) )
{
// log_i( " s" );
windDirection.concat( "S");
}
if ( (adcValue >= 1.7f) & (adcValue < 2.0f ) )
{
// log_i( " w" );
windDirection.concat( "W" );
}
if ( count >= 30 )
{
MQTTinfo.concat( String(kph, 2) );
MQTTinfo.concat( ",");
MQTTinfo.concat( windDirection );
MQTTinfo.concat( ",");
MQTTinfo.concat( String(rain, 2) );
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
MQTTclient.publish( topicWSWDRF, MQTTinfo.c_str() );
xSemaphoreGive( sema_MQTT_KeepAlive );
count = 0;
}
count++;
MQTTinfo = "";
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
}
vTaskDelete ( NULL );
}
// read rainfall
void fRainFall( void *pvParemeters )
{
int count = 0;
pcnt_counter_pause( PCNT_UNIT_1 );
pcnt_counter_clear( PCNT_UNIT_1 );
pcnt_counter_resume( PCNT_UNIT_1 );
for (;;)
{
xEventGroupWaitBits (eg, evtRainFall, pdTRUE, pdTRUE, portMAX_DELAY);
pcnt_counter_pause( PCNT_UNIT_1 );
pcnt_get_counter_value( PCNT_UNIT_1, &count );
pcnt_counter_clear( PCNT_UNIT_1 );
pcnt_counter_resume( PCNT_UNIT_1 );
if ( count != 0 )
{
// 0.2794mm of rain per click clear clicks at mid night
rain = 0.2794f * (float)count;
//log_i( "count %d, rain rain = %f mm", count, rain );
}
if ( (rtc.getHour(true) == 0) && (rtc.getMinute() == 0) )
{
pcnt_counter_pause( PCNT_UNIT_1 );
rain = 0.0;
count = 0;
pcnt_counter_clear( PCNT_UNIT_1 );
pcnt_counter_resume( PCNT_UNIT_1 );
}
}
vTaskDelete ( NULL );
}
////
void fAnemometer( void *pvParameters )
{
//int count = 0;
pcnt_counter_clear(PCNT_UNIT_0);
pcnt_counter_resume(PCNT_UNIT_0);
for (;;)
{
xEventGroupWaitBits (eg, evtAnemometer, pdTRUE, pdTRUE, portMAX_DELAY);
pcnt_counter_pause( PCNT_UNIT_0 );
pcnt_get_counter_value( PCNT_UNIT_0, &count); //int16_t *count
// A wind speed of 2.4km/h causes the switch to close once per second
kph = 2.4f * ((float)count / 60.0f);
/*
if ( count != 0 )
{
log_i( "count %d, wind KPH = %f", count, kph );
}
count = 0;
*/
pcnt_counter_clear( PCNT_UNIT_0 );
pcnt_counter_resume( PCNT_UNIT_0 );
}
vTaskDelete ( NULL );
}
//////
void fmqttWatchDog( void * paramater )
{
int UpdateImeTrigger = 86400; //seconds in a day
int UpdateTimeInterval = 86300; // 1st time update in 100 counts
int maxNonMQTTresponse = 60;
for (;;)
{
vTaskDelay( 1000 );
if ( mqttOK >= maxNonMQTTresponse )
{
ESP.restart();
}
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK++;
xSemaphoreGive( sema_mqttOK );
UpdateTimeInterval++; // trigger new time get
if ( UpdateTimeInterval >= UpdateImeTrigger )
{
TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
UpdateTimeInterval = 0;
}
}
vTaskDelete( NULL );
}
//////
void fparseMQTT( void *pvParameters )
{
struct stu_message px_message;
for (;;)
{
if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
{
// parse the time from the OK message and update MCU time
if ( String(px_message.topic) == topicOK )
{
if ( !TimeSet)
{
String temp = "";
temp = px_message.payload[0];
temp += px_message.payload[1];
temp += px_message.payload[2];
temp += px_message.payload[3];
int year = temp.toInt();
temp = "";
temp = px_message.payload[5];
temp += px_message.payload[6];
int month = temp.toInt();
temp = "";
temp = px_message.payload[8];
temp += px_message.payload[9];
int day = temp.toInt();
temp = "";
temp = px_message.payload[11];
temp += px_message.payload[12];
int hour = temp.toInt();
temp = "";
temp = px_message.payload[14];
temp += px_message.payload[15];
int min = temp.toInt();
rtc.setTime( 0, min, hour, day, month, year );
log_i( "rtc %s ", rtc.getTime() );
TimeSet = true;
}
}
//
} //if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK = 0;
xSemaphoreGive( sema_mqttOK );
}
} // void fparseMQTT( void *pvParameters )#include <ESP32Time.h>
//////
void fReadCurrent( void * parameter )
{
float ADbits = 4096.0f;
float ref_voltage = 3.3f;
uint64_t TimePastKalman = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
SimpleKalmanFilter KF_I( 1.0f, 1.0f, .01f );
float mA = 0.0f;
int printCount = 0;
/*
185mv/A = 5 AMP MODULE
100mv/A = 20 amp module
66mv/A = 30 amp module
*/
const float mVperAmp = 185.0f;
float adcValue = 0;
float Voltage = 0;
float Power = 0.0;
String powerInfo = "";
powerInfo.reserve( 150 );
while ( !MQTTclient.connected() )
{
vTaskDelay( 250 );
}
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 1000; //delay for mS
for (;;)
{
adc1_get_raw(ADC1_CHANNEL_3); // read once discard reading
adcValue = ( (float)adc1_get_raw(ADC1_CHANNEL_3) );
//log_i( "adcValue I = %f", adcValue );
Voltage = ( (adcValue * ref_voltage) / ADbits ) + offSET; // Gets you mV
mA = Voltage / mVperAmp; // get amps
KF_I.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
mA = KF_I.updateEstimate( mA ); // apply simple Kalman filter
TimePastKalman = esp_timer_get_time(); // time of update complete
printCount++;
if ( printCount == 60 )
{
xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY);
Power = CalculatedVoltage * mA;
log_i( "Voltage=%f mA=%f Power=%f", CalculatedVoltage, mA, Power );
printCount = 0;
powerInfo.concat( String(CalculatedVoltage, 2) );
xSemaphoreGive( sema_CalculatedVoltage );
powerInfo.concat( ",");
powerInfo.concat( String(mA, 4) );
powerInfo.concat( ",");
powerInfo.concat( String(Power, 4) );
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
MQTTclient.publish( topicPower, powerInfo.c_str() );
xSemaphoreGive( sema_MQTT_KeepAlive );
powerInfo = "";
}
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
}
vTaskDelete( NULL );
} //void fReadCurrent( void * parameter )
////
void fReadBattery( void * parameter )
{
float adcValue = 0.0f;
const float r1 = 50500.0f; // R1 in ohm, 50K
const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
float Vbatt = 0.0f;
int printCount = 0;
float vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
uint64_t TimePastKalman = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 1000; //delay for mS
for (;;)
{
adc1_get_raw(ADC1_CHANNEL_0); //read and discard
adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
Vbatt = adcValue * vRefScale;
xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
CalculatedVoltage = Vbatt;
xSemaphoreGive( sema_CalculatedVoltage );
/*
printCount++;
if ( printCount == 3 )
{
log_i( "Vbatt %f", Vbatt );
printCount = 0;
}
*/
TimePastKalman = esp_timer_get_time(); // time of update complete
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
//log_i( "fReadBattery %d", uxTaskGetStackHighWaterMark( NULL ) );
}
vTaskDelete( NULL );
}
////
void MQTTkeepalive( void *pvParameters )
{
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
// setting must be set before a mqtt connection is made
MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
for (;;)
{
//check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
{
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
MQTTclient.loop();
xSemaphoreGive( sema_MQTT_KeepAlive );
}
else {
log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
{
connectToWiFi();
}
connectToMQTT();
}
vTaskDelay( 250 ); //task runs approx every 250 mS
}
vTaskDelete ( NULL );
}
////
void connectToWiFi()
{
int TryCount = 0;
while ( WiFi.status() != WL_CONNECTED )
{
TryCount++;
WiFi.disconnect();
WiFi.begin( SSID, PASSWORD );
vTaskDelay( 4000 );
if ( TryCount == 10 )
{
ESP.restart();
}
}
WiFi.onEvent( WiFiEvent );
} // void connectToWiFi()
////
void connectToMQTT()
{
MQTTclient.setKeepAlive( 90 ); // needs be made before connecting
byte mac[5];
WiFi.macAddress(mac);
String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
while ( !MQTTclient.connected() )
{
// boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password, NULL , 1, true, NULL );
vTaskDelay( 250 );
}
MQTTclient.setCallback( mqttCallback );
MQTTclient.subscribe( topicOK );
} // void connectToMQTT()
////
void loop() {}
Thanks Idahowalker, that code looks pretty solid though it's maybe beyond my actual bar.
I was honestly considering removing the call back function as I do not expect commands from outside nor to subscribe to any topic.
Mqtt's only aim in this case Is being fired once every time the button is pushed and communicate the amount of stalls encountered. It works, It can publish data, it's just that after the first run, it somehow affects the ADC reading on pin n.4 and It floors It to 0. Dead nailed to 0. Then in only publishes signal 0 and stalls = 30, as a stall happens 30 times out of 30 in the for loops as signal 0 Is of course <2400 all the time.
This Is where i get clueless
Thank you for your reply!
It is this one
I designed my project based on this pinout, and I can confirm that it behaves like I expect it to as long as I run the first sketch included in my post. As a matter of fact pin 4 (meaning GPIO4, rated as native pin 24 on the chip itself) should be ADC from my understanding of the docs, it uses ADC 2 while pins 32 and above use ADC1. I assume that if I missed the right pin's choice I wouldn't be able to either run the first sketch or the second sketch for its first run.
The second sketch should be an evolution of the first sketch, and this is where the mess happens. When the esp32 is just booted, WIFI's wifi.begin and MQTT's client.connect methods have not been called yet, the analog read goes well and i can publish the results smoothly. I think i might have to investigate more on the libraries used by wifi and mqtt as I suspect they might somehow keep pin4 busy or isolated, even if I thought that in order to not let that happen, purposely calling wifi.disconect() and client.disconnect() befor the end of the loop function would do the job, but I assume I must be wrong somewhere
Using adc2 does incur a penalty as to what the other pins can do. Also, portA pins, which GPIO_NUM_4 is, do not have the same input impendence as those of portB. portB is designed to work with the A:D.
Thank you very much!
You had a point.
Some desoldering and resoldering job and it worked, moved wiring from pin4 to pin 32 and it works like a charm.
Grazie !