How to control a linear actuator with an ESP32 and a BME280 sensor - c++

I'm trying to program an EPS32 board to open and close a linear actuator depending of the temperature a BME 280 sensor gets. It is for an automated gardening project :)
My code is functional but I would like to perfect it.
The actuator is currently connected with two GPIO pin, one to open and he other to close.
GOALS:
Switch off relays when not used.
Replace the use of delay() with millis()
Currently, the actuator is opening when temperature is above 27c°. Relay is on for 7 seconds which let the time to the actuator to go full course. Then, the relay is switch off.
But if the temperature stay above 27, the "if" part of the loop is going on an on, meaning it turn on for 7 seconds, switch off for 7 seconds and so on... I would like to switch all relays off when not needed to save energy and extend components life.
I suppose there might be something to do with && or even the analogRead() function to get the state of the actuator and apply actions from that but it is too complicated for me.
To open the actuator, I decided to time the course of the actuator and let the relay on for that timing with a delay() function. There is probably a different approach to this ( with analogRead() I suppose) but I find it simple and working. I would like to replace delay() with millis() function in order not to block the rest of the script (I plan to add fans, water valves, a float switch sensor...).
May you show me the way ?
#include <Adafruit_BME280.h>
#include <WiFi.h>
const char* ssid = "#####"; // ESP32 and ESP8266 uses 2.4GHZ wifi only
const char* password = "#####";
//MQTT Setup Start
#include <PubSubClient.h>
#define mqtt_server "####.###.##.##"
WiFiClient espClient;
PubSubClient client(espClient);
#define mqttActuator "growShed/Acuator"
#define mqttTemp1 "growShed/temp1"
int actuatorUp = 15; //GPIO de l'actuator
int actuatorDown = 2; //GPIO de l'actuator
int actuatorUpread = (!digitalRead(actuatorUp)); //read state of gpio : on or off
int actuatorDownread = (!digitalRead(actuatorDown)); //read state of gpio : on or off
//MQTT Setup End
Adafruit_BME280 bme1; // I2C
//utiliser les virgules sur les capteurs suivants
float temp1, hum1, pres1;
//gestion des délais entre chaque captations de data
unsigned long millisNow1 = 0; //for delay purposes (laisser 0)
unsigned int sendDelay1 = 2000; //delay before sending sensor info via MQTT
//gestion des délais entre chaque captations de data
unsigned long millisNow3 = 0; //for delay purposes (laisser 0)
unsigned int sendDelay3 = 7000; //delay before sending sensor info via MQTT
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println();
// begin Wifi connect
Serial.println("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(2000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address (wifi RaspPi) : ");
Serial.println(WiFi.localIP());
//end Wifi connect
client.setServer(mqtt_server, 1883);
//BME
delay(5000);
unsigned status;
status = bme1.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x"); Serial.println(bme1.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1);
}
//Acuator
pinMode(actuatorUp, OUTPUT);
digitalWrite(actuatorDown, HIGH); //Begin with actuator switched off
pinMode(actuatorDown, OUTPUT);
digitalWrite(actuatorUp, HIGH); //Begin with actuator switched off
//End Actuator
}
bool getValues() {
temp1 = round(bme1.readTemperature()); //rounded values
actuatorUpread = (digitalRead(actuatorUp)); //inverted value as the relay is inverted
Serial.print("BME 1 Temperature = ");
Serial.print(temp1);
Serial.println(" °C");
Serial.print("État de l'actuator haut = ");
Serial.println(actuatorUpread);
Serial.print("État de l'actuator bas = ");
Serial.print(actuatorDownread);
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
int counter = 0;
while (!client.connected()) {
if (counter==5){
ESP.restart();
}
counter+=1;
Serial.println("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("growTentController")) {
Serial.println("connected");
} else {
Serial.println("failed, rc=");
Serial.println(client.state());
Serial.println(" try again in 5 seconds");
// Wait 10 seconds before retrying
delay(5000);
}
}
}
void loop() {
// put your main code here, to run repeatedly:
if (!client.connected()){
reconnect();
}
if (millis() > millisNow1 + sendDelay1){
if (getValues()) {
client.publish(mqttTemp1, String(temp1).c_str(),true);
client.publish(mqttActuator, String(actuatorUpread).c_str(),true);
millisNow1 = millis();
}
}
//Acuator moving according to BME280 temperature sensor
temp1 = bme1.readTemperature();
if (millis() > millisNow3 + sendDelay3){
if ((temp1 > 27)){
digitalWrite(actuatorUp, LOW);
delay(7000); // approx the time it take to execute the full course of the acuator.
digitalWrite(actuatorUp, HIGH);
}
else {
digitalWrite(actuatorDown, LOW);
delay(7000); // approx the time it take to execute the full course of the acuator
digitalWrite(actuatorDown, HIGH);
}
millisNow3 = millis();
}
}

I think this is what you want to do. This uses a state variable to keep track of what state the actuator is in.
When the actuator is closed, the loop will check the temperature and, if the temperature goes above 27 degrees, it will start opening the actuator. Then the loop will simply monitor the time using millis() until the actuator is open - so you can put other code in the loop for other sensors.
The same happens if the actuator is open, it will close the actuator when the temperature is lower than 26 degrees (kept a degree difference here to stop the code constantly triggering if the temperature hovers around 27 degrees).
Currently this will read the temperature on every iteration of the loop whilst the actuator is either open or closed - so I've put a small delay at the end of the loop to restrict this.
Please note - I have not tested any of the changes in the code as I don't have the hardware to hand. But it compiles, and should give you an idea of how you can use a state model with millis() to handle this sort of thing without delaying the loop.
#include <Adafruit_BME280.h>
#include <WiFi.h>
const char* ssid = "#####"; // ESP32 and ESP8266 uses 2.4GHZ wifi only
const char* password = "#####";
//MQTT Setup Start
#include <PubSubClient.h>
#define mqtt_server "####.###.##.##"
WiFiClient espClient;
PubSubClient client(espClient);
#define mqttActuator "growShed/Acuator"
#define mqttTemp1 "growShed/temp1"
int actuatorUp = 15; //GPIO de l'actuator
int actuatorDown = 2; //GPIO de l'actuator
int actuatorUpread = (!digitalRead(actuatorUp)); //read state of gpio : on or off
int actuatorDownread = (!digitalRead(actuatorDown)); //read state of gpio : on or off
//MQTT Setup End
Adafruit_BME280 bme1; // I2C
//utiliser les virgules sur les capteurs suivants
float temp1, hum1, pres1;
//gestion des délais entre chaque captations de data
unsigned long millisNow1 = 0; //for delay purposes (laisser 0)
unsigned int sendDelay1 = 2000; //delay before sending sensor info via MQTT
//gestion des délais entre chaque captations de data
unsigned long millisNow3 = 0; //for delay purposes (laisser 0)
unsigned int sendDelay3 = 7000; //delay before sending sensor info via MQTT
// The states the actuator can be in.
enum ActuatorState
{
OPENING,
OPEN,
CLOSING,
CLOSED
};
ActuatorState actuatorState;
// When opening or closing the actuator - this is the time to stop.
unsigned long actuatorEndTime = 0 ;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println();
// begin Wifi connect
Serial.println("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(2000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address (wifi RaspPi) : ");
Serial.println(WiFi.localIP());
//end Wifi connect
client.setServer(mqtt_server, 1883);
//BME
delay(5000);
unsigned status;
status = bme1.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x"); Serial.println(bme1.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1);
}
//Acuator
pinMode(actuatorUp, OUTPUT);
digitalWrite(actuatorDown, HIGH); //Begin with actuator switched off
pinMode(actuatorDown, OUTPUT);
digitalWrite(actuatorUp, HIGH); //Begin with actuator switched off
actuatorState = CLOSED ;
//End Actuator
}
bool getValues() {
temp1 = round(bme1.readTemperature()); //rounded values
actuatorUpread = (digitalRead(actuatorUp)); //inverted value as the relay is inverted
Serial.print("BME 1 Temperature = ");
Serial.print(temp1);
Serial.println(" °C");
Serial.print("État de l'actuator haut = ");
Serial.println(actuatorUpread);
Serial.print("État de l'actuator bas = ");
Serial.print(actuatorDownread);
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
int counter = 0;
while (!client.connected()) {
if (counter==5){
ESP.restart();
}
counter+=1;
Serial.println("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("growTentController")) {
Serial.println("connected");
} else {
Serial.println("failed, rc=");
Serial.println(client.state());
Serial.println(" try again in 5 seconds");
// Wait 10 seconds before retrying
delay(5000);
}
}
}
void loop() {
// put your main code here, to run repeatedly:
if (!client.connected()){
reconnect();
}
if (millis() > millisNow1 + sendDelay1){
if (getValues()) {
client.publish(mqttTemp1, String(temp1).c_str(),true);
client.publish(mqttActuator, String(actuatorUpread).c_str(),true);
millisNow1 = millis();
}
}
//Acuator moving according to BME280 temperature sensor
switch ( actuatorState ) {
case OPEN:
// Does it need closing (use value lower than 27 so we're not constantly opening and
// closing the actuator if the temperature is floating around 27)
temp1 = bme1.readTemperature();
if ( temp1 < 26 ) {
digitalWrite(actuatorDown, LOW);
actuatorState = CLOSING;
actuatorEndTime = millis() + 7000 ;
}
break;
case CLOSED:
// Does it need opening?
temp1 = bme1.readTemperature();
if ( temp1 > 27 ) {
digitalWrite(actuatorUp, LOW);
actuatorState = OPENING;
actuatorEndTime = millis() + 7000;
}
break ;
case OPENING:
// Is it fully open?
if ( millis() >= actuatorEndTime ) {
digitalWrite(actuatorUp, HIGH);
actuatorState = OPEN ;
}
break ;
case CLOSING:
// Is it fully closed?
if ( millis() >= actuatorEndTime ) {
digitalWrite(actuatorDown, HIGH);
actuatorState = CLOSED ;
}
break ;
}
// small delay to run the loop - and do the temperature check 5 times per second.
delay(200);
}

Related

ESP32 Bluetooth connection status

I am running into some problems finding a solution when it comes to performing some form of Bluetooth connection check for my project that will allow me to have a connection status light.
My project consists of creating a Bluetooth speaker that has Led Strips controlled over Bluetooth serial (an app will be made to handle this) and audio stream over Bluetooth from a single ESP32.
I have found plenty of examples and had success with performing an spp callback event, however, of course this only works if I connect to the Bluetooth serial side of things through my 'Serial Bluetooth Terminal' app on my phone. If I just go into my phone Bluetooth list and connect to the audio side of things, nothing is registered, which isn't very useful for a Bluetooth speaker!
Basically I really need some help finding a way of registering that a device has connected to the Bluetooth audio so that I can have some form of indication light to tell the user that they are successfully connected to the speaker to play music.
Below is my code:
#include <btAudio.h> //<-------this is the library that I am using to handle Bluetooth audio to an external I2s DAC
#include "BluetoothSerial.h"
#include <FastLED.h>
TaskHandle_t Task1;
//POWER/BT-LIGHT-SETUP----------------------------------------
int powerPinR = 4;
int powerPinG = 16;
int powerPinB = 17;
bool BTisConnected;
//FAST-LED-STUFF----------------------------------------------
CRGB leds[NUM_STRIPS][NUM_LEDS];
CRGB leds_temp[NUM_STRIPS][NUM_LEDS/2];
//BLUETOOTH-SETUP---------------------------------------------
btAudio audio = btAudio("");
BluetoothSerial SerialBT;
//CONNECTION-CHECK--------------------------------------------
void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t*param){
if(event == ESP_SPP_SRV_OPEN_EVT){
Serial.println("Client Connected");
BTisConnected = true;
}
else {
BTisConnected = false;
}
}
//------------------------------------------------------------
void setup() {
//CORE-1-INITIALISE
xTaskCreatePinnedToCore(
codeForTask1, /* Task function. */
"Task_1", /* name of task. */
1000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* Core */
//POWER/BLUETOOTH-CONNECTION-LIGHT-SETUP
pinMode(powerPinR, OUTPUT);
pinMode(powerPinG, OUTPUT);
pinMode(powerPinB, OUTPUT);
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, HIGH);
digitalWrite (powerPinB, HIGH);
//COOLDOWN-DELAY
delay(3000);
//AUDIO-INITIALISE
audio.begin();
int bck = 26;
int ws = 27;
int dout = 25;
audio.I2S(bck, dout, ws);
//LED-STRIP-SETUP-&-CLEAR-ALL
FastLED.addLeds<WS2812B,STRIP1PIN,GRB>(leds[0], NUM_LEDS);
FastLED.addLeds<WS2812B,STRIP2PIN,GRB>(leds[1], NUM_LEDS);
FastLED.clear();
FastLED.show();
//SERIAL-INITIALISE-&-CLIENT-CONNECTION-CHECK
Serial.begin(115200);
SerialBT.begin("Pilot"); //<-----BLUETOOTH NAME
SerialBT.register_callback(callback); //<-- SerialBT connection check works perfectly, but nothing for audio connection! :(
}
//CORE-0-VOID-LOOP--------------------------------------------
void codeForTask1( void * parameter )
{
for (;;) {
manageData();
delay(10);
}
}
//CORE-1-VOID-LOOP--------------------------------------------
void loop() {
BTconnectionCheck();
playScene();
}
//MANAGE-INCOMING-BLUETOOTH-SERIAL-DATA-----------------------------------------------
void manageData() {
//READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT **
char rawData[100] = "";
char keyword[] = "Mydata=";
if (SerialBT.available() > 0) {//new data in
size_t byteCount = SerialBT.readBytesUntil('\n', rawData, sizeof(rawData) - 1); //read in data to buffer
rawData[byteCount] = NULL;//put an end character on the data
const char delimiter[] = ",";
char parsedStrings[5][8]; //first number = how many bits of data - 2nd number = max size of eeach data
int dataCount = 0;
int dataPosition = 0;
char *token = strtok(&rawData[dataPosition], delimiter);//look for first piece of data after keyword until comma
if (token != NULL && strlen(token) < sizeof(parsedStrings[0])) {
strncpy(parsedStrings[0], token, sizeof(parsedStrings[0]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[0], NULL);
}
for (int i = 1; i < 5; i++) {
token = strtok(NULL, delimiter);
if (token != NULL && strlen(token) < sizeof(parsedStrings[i])) {
strncpy(parsedStrings[i], token, sizeof(parsedStrings[i]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[i], NULL);
}
}
if (dataCount == 5) {
scene = atoi (parsedStrings[0]);
hue = atoi(parsedStrings[1]);
saturation = atoi(parsedStrings[2]);
brightness = atoi(parsedStrings[3]);
eventInterval = atol (parsedStrings[4]);
}
}
}
//BLUETOOTH-CONNECTION-CHECK---------------------------------------------------------
void BTconnectionCheck(){
SerialBT.register_callback(callback);
if (BTisConnected == true){
bluetoothConnected();
}
else {
bluetoothSearch();
}
}
void bluetoothSearch(){
digitalWrite (powerPinR, LOW);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
void bluetoothConnected(){
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
I have cut lots of the code to do with the LEDs out but its still quite long, If it would help to have a more condensed version then I will chop it down further. Or if it helps to have the full code then I can also post it.
Any help would be greatly appreciated as I am well and truly stuck with this one and its a pretty important part of the project.
Thanks in advance!

Lidar Sensors not working properly - How to work with two lidar Sensors over I2C on arduino

I'm currently working on a project with some friends about lidar measuraments based on ARDUINO and GARMIN Lidar v3HP and we are getting some reading that are questionable from the sensors. They seem to work but the measurements are not correct.
We have issues with the data and also with the address, we setup the sensors with two different addresses 0x42 and 0x43, but one of the sensors keeps on the default address.
#include <Arduino.h>
#include <Wire.h>
#include <stdint.h>
#include <LIDARLite_v3HP.h>
#include <I2CFunctions.h>
#define POWER_ENABLE_S1 12
#define POWER_ENABLE_S2 11
#define DEFAULT_ADDRESS 98
#define FAST_I2C
#define NUMERO_LIDARS 2
LIDARLite_v3HP Sensor1;
LIDARLite_v3HP Sensor2;
int detectedAddreses[NUMERO_LIDARS];
int currentAdd;
int deviceCount = 0;
int i = 0;
void scanI2C()
{
int nDevices = 0;
while (i < NUMERO_LIDARS)
{
for (byte addr = 1; addr < 127; ++addr)
{
Wire.beginTransmission(addr);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial.print("Se encontro un dispositivo en ");
Serial.print(addr);
Serial.println(" !");
++nDevices;
detectedAddreses[i] = addr;
if (addr == DEFAULT_ADDRESS)
{
configSensors(i, 66 + deviceCount, addr);
detectedAddreses[i] = addr;
i++;
}else{
detectedAddreses[i] = addr;
i++;
}
}
else if (error == 4)
{
Serial.print("Error desconocido en ");
Serial.println(addr);
}
}
if (nDevices == 0)
{
Serial.println("No se encontraron dispositivos\n");
}
else
{
Serial.println("Terminado\n");
}
}
}
void configSensors(int sensor, uint8_t new_address, uint8_t old_address)
{
switch (sensor)
{
case 0:
Sensor1.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S1, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor1.configure(0,new_address);
break;
case 1:
Sensor2.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S2, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor2.configure(0,new_address);
i = 999;
break;
case 2:
break;
}
}
void setup()
{
Serial.begin(115200);
#ifdef FAST_I2C
#if ARDUINO >= 157
Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
#else
TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
#endif
#endif
pinMode(POWER_ENABLE_S1, OUTPUT);
pinMode(POWER_ENABLE_S2, OUTPUT);
digitalWrite(POWER_ENABLE_S1, HIGH);
digitalWrite(POWER_ENABLE_S2, HIGH);
Wire.begin();
scanI2C();
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,HIGH);
Sensor1.configure(3,detectedAddreses[0]);
Sensor2.configure(3,detectedAddreses[1]);
}
void measure(){
float s1;
float s2;
Sensor1.waitForBusy();
Sensor1.takeRange();
Sensor1.waitForBusy();
s1 = Sensor1.readDistance(detectedAddreses[0]);
Sensor2.waitForBusy();
Sensor2.takeRange();
Sensor2.waitForBusy();
s2 = Sensor2.readDistance(detectedAddreses[1]);
Serial.println("Sensor 1: " + String(s1) + "; Sensor 2: " + String(s2));
}
void loop()
{
/*Serial.println(detectedAddreses[0]);
Serial.println(detectedAddreses[1]);*/
measure();
}
Based on your top comment, there may be an issue with configuring both lidars at the same time.
From factory default, they will both respond to the default I2C address 0x62. So, when you try to reconfigure one at a time, they will both respond [and there may be a race condition] and will both get programmed to the new I2C address.
If [and this is a big if] the lidar can save the configuration to non-volatile storage on the unit, you can connect one at a time [physically/manually] and give them different addresses. The unit saves the address. And, next time, will only respond to the "new" address.
Then, after both units have been reconfigured, you can then connect both simultaneously and they will respond individually [as desired].
I looked at the .pdf and the wiring diagram. You may be able to connect the lidar's power pin [or enable pin] to an Arduino GPIO port pin (instead of +5V). Then, you can control the power up of each unit individually. Then, you can reconfigure both as above. That is, assert power to one, reconfigure it, power it down [with the saved config]. Do this for the other unit. Then, you can power up both units [at this point, they are responding to different I2C addresses].
Don't know if Garmin starts up the lasers immediately or whether you have to give it a "start" command. Being able to control power individually may be a good thing if there is no separate start command.
I'm not familiar with Garmin's lidars, but I've written S/W to control Velodyne lidars and we had to apply power in a staggered manner because the power surge when they both started up would "brown out" the system. With Garmin, YMMV.
If all else fails, you may have to put each unit on a separate/different physical I2C bus [because you can't reconfigure them separately].
Here's the working code,
The sensors are hocked up in the same I2C bus, power enable pins to each sensor and ground conected to arduino. Power to the sensors is supplied by a 11.1V battery with a power regulator to 5V
#include <Arduino.h>
#include <Wire.h>
#include <stdint.h>
#include <LIDARLite_v3HP.h>
#include <I2CFunctions.h>
#define POWER_ENABLE_S1 12
#define POWER_ENABLE_S2 11
#define DEFAULT_ADDRESS 98
#define FAST_I2C
#define NUMERO_LIDARS 2
LIDARLite_v3HP Sensor1;
LIDARLite_v3HP Sensor2;
int detectedAddreses[NUMERO_LIDARS];
int currentAdd;
int deviceCount = 0;
int i = 0;
void scanI2C()
{
int nDevices = 0;
while (i < NUMERO_LIDARS)
{
for (byte addr = 1; addr < 127; ++addr)
{
Wire.beginTransmission(addr);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial.print("Se encontro un dispositivo en ");
Serial.print(addr);
Serial.println(" !");
++nDevices;
detectedAddreses[i] = addr;
if (addr == DEFAULT_ADDRESS)
{
configSensors(i, 66 + deviceCount, addr);
detectedAddreses[i] = addr;
i++;
}else{
detectedAddreses[i] = addr;
i++;
}
}
else if (error == 4)
{
Serial.print("Error desconocido en ");
Serial.println(addr);
}
}
if (nDevices == 0)
{
Serial.println("No se encontraron dispositivos\n");
}
else
{
Serial.println("Terminado\n");
}
}
}
void configSensors(int sensor, uint8_t new_address, uint8_t old_address)
{
switch (sensor)
{
case 0:
Sensor1.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S1, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor1.configure(0,new_address);
break;
case 1:
Sensor2.setI2Caddr(new_address, 0, old_address);
digitalWrite(POWER_ENABLE_S2, LOW);
//detectedAddreses[sensor] = new_address;
deviceCount++;
Sensor2.configure(0,new_address);
i = 999;
break;
case 2:
break;
}
}
void setup()
{
Serial.begin(115200);
#ifdef FAST_I2C
#if ARDUINO >= 157
Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
#else
TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
#endif
#endif
pinMode(POWER_ENABLE_S1, OUTPUT);
pinMode(POWER_ENABLE_S2, OUTPUT);
digitalWrite(POWER_ENABLE_S1, HIGH);
digitalWrite(POWER_ENABLE_S2, HIGH);
Wire.begin();
scanI2C();
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,HIGH);
Sensor1.configure(3,detectedAddreses[0]);
Sensor2.configure(3,detectedAddreses[1]);
}
void measure(){
float s1;
float s2;
digitalWrite(POWER_ENABLE_S1,HIGH);
digitalWrite(POWER_ENABLE_S2,LOW);
delay(25);
Sensor1.waitForBusy();
Sensor1.takeRange();
Sensor1.waitForBusy();
s1 = Sensor1.readDistance(detectedAddreses[0]);
digitalWrite(POWER_ENABLE_S1,LOW);
digitalWrite(POWER_ENABLE_S2,HIGH);
delay(25);
Sensor2.waitForBusy();
Sensor2.takeRange();
Sensor2.waitForBusy();
s2 = Sensor2.readDistance(detectedAddreses[1]);
Serial.println("Sensor 1: " + String(s1) + "; Sensor 2: " + String(s2));
}
void loop()
{
/*Serial.println(detectedAddreses[0]);
Serial.println(detectedAddreses[1]);*/
measure();
}

Set up loop keeps looping (Adurino)

I am currently troubleshooting a code in Arduino for a temperature and humidity project. There is a line in the void setup(), Serial.println("Feather LoRa TX Test!");, which keeps popping up. My ideal code is to run that particular line once in the output and that will be it. However, the current code keeps repeating that line again, and again. May I know how do I rectify this issue (The whole code is below)? Thanks in advance!!
#include <RH_RF95.h>
#include <DHT.h>
#define DHTPIN 7 // what digital pin we're connected to
#define DHTTYPE DHT22 // DHT 11
DHT dht(DHTPIN, DHTTYPE);
#define RFM95_CS 10
#define RFM95_RST 9
#define RFM95_INT 3
// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 915.0
// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);
int node = 3; // to change based on node deployment
void setup()
{
pinMode(RFM95_RST, OUTPUT);
digitalWrite(RFM95_RST, HIGH);
while (!Serial);
Serial.begin(9600);
delay(100);
Serial.println("Feather LoRa TX Test!");
digitalWrite(RFM95_RST, LOW);
delay(100);
digitalWrite(RFM95_RST, HIGH);
delay(100);
while (!rf95.init()) {
Serial.println("LoRa radio init failed");
while (1);
}
Serial.println("LoRa radio init OK!");
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
if (!rf95.setFrequency(RF95_FREQ)) {
Serial.println("setFrequency failed");
while (1);
}
Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
dht.begin();
rf95.setTxPower(23, false);
}
void loop()
{
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
delay(1000);
return;
}
String d = "{\"Node\":"+ String (node) +",";
d += "\"Temp\":"+ String (t)+",";
d += "\"Hum\":"+ String (h);
d += "} "; // Add a trailing space is necessary
Serial.println("Transmitting...");
char data[d.length()];
d.toCharArray(data,d.length());
Serial.println(d);
rf95.send((uint8_t*)data, sizeof(data));
Serial.println("Waiting for packet to complete...");
delay(1000);
rf95.waitPacketSent();
Serial.println(" complete...");
delay(57000); // delay 1 minute
}
You have an infinite loop before you do any initialization. This will be detected because Arduino have a watchdog timer, and the system will reset.
And on reset setup is called again, and you again enter the infinite loop.
The loop it's about:
while (!Serial);
You must call Serial.begin(...) before that loop:
Serial.begin(9600);
while (!Serial);
Something is resetting your MCU before the code reaches the loop function. Therefore the setup function gets executed again and again. You can add more print messages in between lines so you'll know where it breaks.

Arduino simple timed loop without delay() - millis() doesn't work?

Have some arduino code for temp loggers that is VERY NEARLY working....!
I've built an OTA routine so I can update them remotely, however the delay() loop I had to ensure it only logged temperatures every 15 mins is now causing problems as it effectively freezes the arduino by design for 15mins, meaning OTA wouldn't work whilst it is in this state.
Some suggestions say just to flip to millis() instead, but I can't seem to get this working and it's logging ~20 records every second at the moment.
Ideally I just want delay_counter counting up to the value in DELAY_TIME, then running the rest of the code and resetting the counter.
Can anyone help me and point out what I'm doing daft in my code???
// v2 Temp sensor
// Connecting to Home NAS
#include <DHT.h>
#include <DHT_U.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <InfluxDbClient.h>
#define SSID "xxx" //your network name
#define PASS "xxx" //your network password
#define VersionID "v3"
#define SensorName "ServerUnit" //name of sensor used for InfluxDB and Home Assistant
// Temp Sensor 1 - GardenTropical
// Temp Sensor 2 - GardenRoom
// Temp Sensor 3 - Greenhouse
// Temp Sensor 4 - OutsideGreenhouse
// Temp Sensor 5 - ServerUnit
// Connection Parameters for Jupiter InfluxDB
#define INFLUXDB_URL "http://192.168.1.5:8086"
#define INFLUXDB_DB_NAME "home_assistant"
#define INFLUXDB_USER "xxx"
#define INFLUXDB_PASSWORD "xxx"
// Single InfluxDB instance
InfluxDBClient client(INFLUXDB_URL, INFLUXDB_DB_NAME);
// Define data point with measurement name 'DaveTest`
Point sensor("BrynyneuaddSensors");
#define PORT 80
#define DHTPIN 4 // what pin the DHT sensor is connected to
#define DHTTYPE DHT22 // Change to DHT22 if that's what you have
#define BAUD_RATE 115200 //Another common value is 9600
#define DELAY_TIME 900000 //time in ms between posting data to Home Server
unsigned long delay_counter = 0;
DHT dht(DHTPIN, DHTTYPE);
//this runs once
void setup()
{
Serial.begin(BAUD_RATE);
// Connect to WIFI
WiFi.begin(SSID, PASS);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print("*");
}
// Initialise OTA Routine
ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
//initalize DHT sensor
dht.begin();
// set InfluxDB database connection parameters
client.setConnectionParamsV1(INFLUXDB_URL, INFLUXDB_DB_NAME, INFLUXDB_USER, INFLUXDB_PASSWORD);
// Add constant tags - only once
sensor.addTag("device", SensorName);
// Check server connection
if (client.validateConnection()) {
Serial.print("Connected to InfluxDB: ");
Serial.println(client.getServerUrl());
} else {
Serial.print("InfluxDB connection failed: ");
Serial.println(client.getLastErrorMessage());
Serial.println(client.getServerUrl());
Serial.println("Exiting DB Connection");
}
}
//this runs over and over
void loop() {
ArduinoOTA.handle();
float h = dht.readHumidity();
Serial.print("Humidity: ");
Serial.println(h);
// Read temperature as Fahrenheit (isFahrenheit = true)
float c = dht.readTemperature();
Serial.print("Temperature: ");
Serial.println(c);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(c)) {
Serial.println("Reading DHT22 Failed, exiting");
return;
}
//update Influx DB channel with new values
updateTemp(c, h);
Serial.print("Writing to InfluxDB: ");
//INFLUXDB - clear temp data so it doesn't repeat
sensor.clearFields();
// Update Influx DB
sensor.addField("Temperature", c);
sensor.addField("Humidity", h);
Serial.println(sensor.toLineProtocol());
// Write data
client.writePoint(sensor);
//wait for delay time before attempting to post again
if(millis() >= DELAY_TIME){
delay_counter += 0;
}
//Increment Delay Counter
delay_counter++;
}
bool updateTemp(float tempC, float humid) {
WiFiClient client; // Create a WiFiClient to for TCP connection
Serial.println("Receiving HTTP response");
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
Serial.println();
Serial.println("Closing TCP connection");
client.stop();
return true;
}
Set a TimerObject. this seems to be what you want.
Download the Arduino TimerObject code from github and follow the installation instructions
#include "TimerObject.h"
Create the callback function
Create the TimerObject
Setup the TimerObject and periodically call update() in your loop():
// make sure to include the header
#include "TimerObject.h"
...
// setup your TimerObject
TimerObject* sensor_timer = new TimerObject(15 * 60 * 1000); // milliseconds
...
// define the stuff you want to do every 15 minutes and
// stick it in a function
// not sure what from your loop() needs to go in here
void doSensor()
{
float h = dht.readHumidity();
Serial.print("Humidity: ");
Serial.println(h);
// Read temperature as Fahrenheit (isFahrenheit = true)
float c = dht.readTemperature();
Serial.print("Temperature: ");
Serial.println(c);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(c)) {
Serial.println("Reading DHT22 Failed, exiting");
return;
}
//update Influx DB channel with new values
updateTemp(c, h);
Serial.print("Writing to InfluxDB: ");
//INFLUXDB - clear temp data so it doesn't repeat
sensor.clearFields();
// Update Influx DB
sensor.addField("Temperature", c);
sensor.addField("Humidity", h);
Serial.println(sensor.toLineProtocol());
// Write data
client.writePoint(sensor);
}
...
// add the timer setup to your setup()
// probably at the end is a good place
void setup()
{
...
// lots of stuff above here
sensor_timer->setOnTimer(&doSensor);
sensor_timer->Start();
}
// modify your loop() to check the timer on every pass
void loop()
{
ArduinoOTA.handle();
sensor_timer->Update();
}
If you don't want to wait 15 minutes for the first call of doSensor, you can explicitly call it at the end of your setup() function before you start the timer.
Here is an simple example how to use millis()
int last_report = -777;//dummy value
int REPORT_INTERVAL = 15 *60 ; // 15 minutes
void loop() {
ArduinoOTA.handle();
int interval = millis() / 1000 - last_report;
if (interval < REPORT_INTERVAL) {
return;
}
last_report = millis() / 1000;
//do some important stuff
}
Make it simole and use easy code:
const unsigned long timeIntervall = 15*60*1000; // 15 minutes
unsigned long timeStamp = 0;
void setup(){....}
void loop() {
ArduinoOTA.handle(); // is running all the time
// Code in this section only runs every timeIntervall - rollover safe
if(millis() - timeStamp > timeIntervall ){
float h = dht.readHumidity();
......
// Write data
client.writePoint(sensor);
timeStamp = millis(); // reset the timer
}
}

Arduino wireless servo code

I'm trying to make a contraption where you press a button on one board and it moves the servo either to 90 degrees or 180 degrees on the other board. If it's at 90 then it moves to 180 and vice versa.
I'm not very knowledgeable when it comes to this stuff as this is my first major project so bear with me. I already have the wireless system working (thanks to hours of Googling) and a toggle system for an LED (for testing to see if the wireless is working).
I'm using one of the tiny RF transmitters, two Nanos, and a servo from Radio Shack. The problem is the servo doesn't turn but my test LED turns on and off. Here is the code for the receiver end of things:
#include <VirtualWire.h>
#include <ServoTimer2.h>
const int releu_pin = 9;
const int servoPin = 6;
const int transmit_pin = 12;
const int receive_pin = 3;//pin connected between RX module and Arduino
const int transmit_en_pin = 5;
ServoTimer2 myservo;
void setup() {
myservo.attach(servoPin);
myservo.write(45);
vw_set_tx_pin(transmit_pin);
vw_set_rx_pin(receive_pin);
vw_set_ptt_pin(transmit_en_pin);
vw_set_ptt_inverted(true);
vw_setup(2000);//speed communication bps
vw_rx_start(); // activate receiving mode
pinMode(releu_pin, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT); //Debug
}
void loop() {
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) {
//verify if any data is received
if(buf[0]=='1') {
//if received 1 turn ON releu_pin
myservo.write(90);
digitalWrite(releu_pin , HIGH);
digitalWrite(LED_BUILTIN, HIGH); //Debug
delay(100);
}
if(buf[0]=='0') {
myservo.write(180);
digitalWrite(releu_pin , LOW);
digitalWrite(LED_BUILTIN, LOW); //Debug
delay(100);
}
}
}