Hello everyone, I'm using an R4 Wi-Fi for a mobile weather station, and my issue with it is that it is seriously struggling to connect to the internet, and when it does, it stays for a little bit, then loses connection, and it might connect again, but it will just disconnect again. I decided to try making an amplifier by a metal can an attaching a wire to the antenna of the ESP32 on the board, and for a while it worked great! But then it started acting up again.
Any help is appreciated.
Thank you!
Here is the code I'm using on the Cloud editor:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
/*
Sketch generated by the Arduino IoT Cloud Thing "Untitled"
https://create.arduino.cc/cloud/things/28ee1cf9-8278-4378-9684-6061f2d8aff8
Arduino IoT Cloud Variables description
The following variables are automatically generated and updated when changes are made to the Thing
String systemMessages;
float rain;
float sunlight;
int hours;
int humidity;
int minutes;
int temperature;
CloudLocation location;
bool timeset;
CloudTime timer;
Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
which are called when their values are changed from the Dashboard.
These functions are generated with the Thing and added at the end of this sketch.
*/
#include "RTC.h"
#include <Arduino_MKRGPS.h>
#include "thingProperties.h"
#include <AM2302-Sensor.h>
constexpr unsigned int SENSOR_PIN {7U};
AM2302::AM2302_Sensor am2302{SENSOR_PIN};
int rainPin = 0;
uint8_t r, g, b;
int RED_LED = 13;
int GREEN_LED = 12;
int BLUE_LED = 11;
int White_Led = 10;
int Red_Led = 9;
LiquidCrystal_I2C lcd(0x27,20,4);
int connectTimes = 0;
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
lcd.init();
lcd.init();
lcd.backlight();
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
do {
delay(100);
lcd.clear();
lcd.print("Connecting...");
connectTimes++;
if (connectTimes >= 100){
lcd.clear();
lcd.print("Connection");
lcd.setCursor(0,1);
lcd.print("Failed!!!");
delay(3000);
lcd.clear();
lcd.print("Please check");
lcd.setCursor(0,1);
lcd.print("All connections...");
connectTimes == 0;
delay(3000);
loop();
}
} while(1);
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(4);
ArduinoCloud.printDebugInfo();
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
pinMode(White_Led, OUTPUT);
pinMode(Red_Led, OUTPUT);
pinMode(rainPin, INPUT);
RTC.begin();
lcd.clear();
lcd.print("Connected!");
delay(2000);
}
void loop() {
ArduinoCloud.update();
if (timeset == true){
RTCTime mytime(timer);
RTC.setTime(mytime);
lcd.clear();
lcd.print("Setting time...");
}
RTCTime currenttime;
RTC.getTime(currenttime);
hours = currenttime.getHour();
minutes = currenttime.getMinutes();
float latitude = GPS.latitude();
float longitude = GPS.longitude();
float altitude = GPS.altitude();
float speed = GPS.speed();
int satellites = GPS.satellites();
location = Location(latitude, longitude);
auto status = am2302.read();
float TempF = (am2302.get_Temperature() * 1.8) + 25;
float Humidity = am2302.get_Humidity();
temperature = TempF;
humidity = Humidity;
sunlight = analogRead(A0) * (12.0 / 1023.0);
rain = digitalRead(rainPin);
lcd.clear();
lcd.print("Temp: ");
lcd.print(TempF);
lcd.print("F");
lcd.setCursor(0, 1);
lcd.print("Humidity: ");
lcd.print(Humidity);
lcd.print("%");
// Serial.print(currenttime.getDayOfMonth());
// Serial.print("/");
// Serial.print(Month2int(currenttime.getMonth()));
// Serial.print("/");
// Serial.print(currenttime.getYear());
// Serial.print(" - ");
// Print time (HH/MM/SS)
//Serial.print(":");
//Serial.println(currenttime.getSeconds());
// Your code here
digitalWrite(RED_LED, r);
digitalWrite(GREEN_LED, g);
digitalWrite(BLUE_LED, b);
if (hours >= 16 && hours < 7) {
digitalWrite(White_Led, LOW);
digitalWrite(Red_Led, HIGH);
}
if (hours > 7 && hours < 16){
digitalWrite(White_Led, HIGH);
digitalWrite(Red_Led, LOW);
}
}
void onColorChange() {
}
void onSunlightChange() {
}
void onRainChange() {
}
void onLocationChange() {
}
void onButtonsChange() {
}
void onTimerChange() {
}
void onMinutesChange() {
}
void onHoursChange() {
}
void onTimsetChange() {
}
void onTimesetChange() {
}
/*
Since SystemMessages is READ_WRITE variable, onSystemMessagesChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSystemMessagesChange() {
// Add your code here to act upon SystemMessages change
}
Well, the weather station is mobile, so it can move around the yard and record data from different places, but it probably will at most be about 300 feet at most. But the router is also inside the house, so it would have to go through the walls as well...
Well, it's currently still under construction, so I currently have the machine inside my house because it is too cold to work on it outside, so right now it's right across the room from the router, but it's still having the issues.
WiFi is very short distance, depending on freq. 5GHz is very short, the older 2.4GHz goes much farther and penetrates walls better. ESP-NOW has much greater range, over 500ft (2 football fields) BUT you can put it in long range mode if you can put up with a little less bandwidth and get at least 500m and even as far as 1Km (for the US readers, that's 1,600ft to 3280ft)
It is built into every esp32. Just look at the examples in the esp-now library, it's dead simple. Here is an article with all you need https://dronebotworkshop.com/esp-now/
Monitor the WiFi RSSI Signal strength parameter and track its changes over time. WiFi is very susceptible to metal or other obstructions. You might be able to get it to operate over those distances with the right antennas and a clear line of sight. There are various higher gain antennas that would probably help a lot.
I'll probably try the ESP-NOW protocol like @sonofcy suggested, then I'll try monitoring the signal strength...
And do you monitor the signal strength through the serial port? And what sort of code would that take?
As for obstructions, The R4 is going to be encased in a metal box, but I have an antenna wire I attached to the board that leads up and out of the box into a small metal can which I plan to keep directed to the router at all times. Would this be the kind of antenna that you would suggest?
No, antenna design is an entire science. The first thing you have to do is to remove the existing antenna, many boards use a zero ohm smd jumper for that purpose. Why metal, 3D print a PLA case. I guarantee that you have a friend with a printer. Don't bother with signal strength, that is a expensive instrument, just set up a simple transmitter and receiver and transmit a small message with an ascending count as part of it then start walking. If ESP-NOW can't do the job, LORA is the next step, but it is bare, you need to invent your own protocol. Mine includes length at the start, inverse length at the end, and a few special bit patterns. LORA can go 10's of Km under the right conditions.
And once that is jumped, how do you connect another antenna?
Because on the R4, the only antenna I saw without my modification was a small squiggly strip on the board next to the ESP32 chip, and what I did was expose the antenna, then solder the antenna wire to the copper squiggly line.
As for the housing, I do have friend with a 3D printer, metal was just what I had on hand from an old car radio system, and it was convenient because I grounded the entire box so that I could attach grounding wires anywhere on the box.
Now it's even stranger!
I decided to try running a different program, so I chose the "SimpleWebServerWiFi" example included on the R4 Wi-Fi, and it worked!
But when I tried the code I made in the first post, it didn't work...
And I did make sure that all the network credentials were correct, still nothing.
A good antenna is very dependent on the WAVELENGTH (frequency) of the signals being sent. There are specific geometries and dimensions that can maximize the antenna gain (efficiency). Putting an antenna in a can pointed in a certain direction is as likely to diminish the signal as it might be to enhance it unless you get the dimensions right. You can achieve quite a bit of additional gain by making an antenna directional if that's a feasible approach for your application.
It will be obvious, there will be a tiny round connector for the external antenna but the R4 doesn't have one.
Soldering that piece of wire to the antenna is guaranteed to not only reduce the signal strength and range, but the worst case is it could destroy the ESP32. It's been years since I studied antenna design but the basics are quite simple. A given frequency means the transmitted wave is x meters long. For example one of the frequencies of WiFi is 2.4GHz. That is a wavelength of 0.12491352 Meters or 12.491352 cm which is 4.92 in (rounded to 2 decimal positions) However, we seldom use a full wave antenna, a 1/4 wave is common so the antenna would be roughly 1.23 in. The actual length of a genuine 1/4 wave is 1.22946378 in and any deviation from that will reduce the strength therefore range of the signal. Yes there are tricks that allows the physical antenna to be larger or smaller than the required length but electrically it will be exactly 1.22946378 in. I hope you get the message.
Are you referring to the code in post #1? That is IoT cloud code, there are lots of reasons it might fail, for instance did you have the CloudAgent running?
Because cloud apps are more complex there are more points of failure. Newer folks often have difficulty understanding that. After over 50 years experience with many operating systems and languages I am not surprised it didn't work for you yet.
Some of that code looks weird, I recommend starting with something much simpler to give you confidence it does work.
Well, I have the cloud agent, but I thought it was just for USB port access... Because without the cloud agent, I could still do OTA updates, but I couldn't do a USB port upload. So, I don't think the Cloud agent is the problem, and the code is probably the problem, but whenever I add what I think is necessary, a similar problem occurs. I think I just need help with code structure...
And I will probably remove the antenna I made seeing as it sounds as if it was useless...
I never heard of that re the Agent. Any cloud app I have created 90% of the code was auto created and my 10% was INSIDE THE ONCHANGE functions.
Here is my simple LED sketch, can you see why I am concerned?
void setup() {
Serial.begin(9600); // Initialize serial and wait for port to open:
delay(1500); // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
// Defined in thingProperties.h
initProperties();
ArduinoCloud.begin(ArduinoIoTPreferredConnection); // Connect to Arduino IoT Cloud
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
pinMode(LED_BUILTIN, OUTPUT);
}
The do {...} while (1); means you never exit the function, that makes no sense.
Sorry, there is just too much weirdness for me to fix the code. TBH I am surprised it works at all.
Well, that block of code is so that if it takes too long to connect it will tell me that "Connection Failed!" on the LCD screen, so if there is a way to get it to tell me when it is connecting and then when it is connected, that would be what I'm trying to do in this section.
Well, now I know not to use the "do-while" type loop, so I tried the "for" loop type, but it still didn't work, and I doubt that a "switch-case" will help either...
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
lcd.init();
lcd.init();
lcd.backlight();
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
for (connectTimes = 0; connectTimes <= 200; connectTimes++){
lcd.print("Connecting...");
delay(100);
}
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(4);
ArduinoCloud.printDebugInfo();
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
pinMode(White_Led, OUTPUT);
pinMode(Red_Led, OUTPUT);
pinMode(rainPin, INPUT);
RTC.begin();
lcd.clear();
lcd.print("Connected!");
delay(2000);
}
And I also know that if I simply don't have a loop to tell the screen to say "connecting..." It will say "Connecting..." for a split second, then say, "Connected!" even when it's not.
Is there a type of loop that won't interrupt the program?
And should I try to put the "void loop()" code into the "On-Change" functions that were generated?
TWO things. First take a course in programming. Second, let the cloud write your code, do not add any code that is outside the event change blocks the cloud inserted for you. ALL the connectivity is handled by the cloud. You may not like the way it's handled, but if you try to fix it you will end up in this situation. You need to understand the limits of WiFi, 300 ft is a stretch and that is only over water or unobstructed land. If your router is in the house how many walls are between the router and the station. It gets even worse with more current WiFi frequencies. I have a bunch of WiFi 6 and 6e in my small apartment. The repeaters are free from the ISP so it's not overselling. 6 is great for bandwidth (I have a 1Meg internet connection, fiber optic) but can't go through concrete walls very well.
Here is an example of a Arduino IoT cloud app that has NO sketch, it is all done with cloud variables, properties and built-in code. It is so big I need two screen shots of my laptop screen. There is actually a third screen but it is just a continuation of the last two large objects.
Here is their startup code. The only significant code addition to startup is the beginSensors function which I have also posted. Again, nothing in that code is cloud oriented, it is just normal sensor setup.
What you need is first learn to program, then search and read. Hundreds of people have built what you are wanting to build, learn from the countless examples.
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
Serial.println("\r\nArduino Weather Station Demo");
beginSensors();
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection, true);
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(4);
ArduinoCloud.printDebugInfo();
Serial.println("Setup finished!");
}
void beginSensors()
{
// Set up pins
pinMode(pinSoilSignal, INPUT);
pinMode(pinSoilPower, OUTPUT);
pinMode(pinAS3935Int, INPUT);
attachInterrupt(digitalPinToInterrupt(pinAS3935Int), lightningInterrupt, RISING);
// Begin weather meter kit
setWeatherMeterKitParams();
weatherMeterKit.begin();
// Begin communicaiton busses
Wire.begin();
SPI.begin();
// Begin sensors on busses
bme280Connected = myBME280.beginI2C();
veml6075Connected = myVEML6075.begin();
as3935Connected = myAS3935.beginSPI(pinAS3935CS);
if(bme280Connected)
{
Serial.println("BME280 connected!");
}
else
{
Serial.println("BME280 not connected!");
}
if(veml6075Connected)
{
Serial.println("VEML6075 connected!");
}
else
{
Serial.println("VEML6075 not connected!");
}
if(as3935Connected)
{
Serial.println("AS3935 connected!");
}
else
{
Serial.println("AS3935 not connected!");
}
}