esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.08k stars 13.33k forks source link

Connect to AP using SSID, Password, and BSSID? How exactly? #9163

Closed madmacks59 closed 4 months ago

madmacks59 commented 4 months ago

Platform

Problem Description

I've been trying to connect to a specific AP using its SSID/Password and the MAC address of the AP. I have several APs spread around my property and most of my devices attach to the strongest AP. In my particular application I want the ESP8266 to connect to a specific AP and ignore all the others. To do this I should be able to use the "WiFi.begin(ssid, password, channel, bssid, connect)" option.

But, I've tried multiple ways to define the bssid parameter properly and none of the are working. Can someone provide an example of how exactly to do this within the Arduino IDE?

And example of the definition code and the call code would really help...

JAndrassy commented 4 months ago

https://arduino-esp8266.readthedocs.io/en/3.1.2/esp8266wifi/station-class.html#begin

madmacks59 commented 4 months ago

Yes, I know, I’ve read that…what I’m looking for is an example of the implementation in code. For example, do i use the call like…

WiFi.begin(“myssid”, “mypassword”, 7, “01:02:C1:33:F1”) Or do I define variables and pass them (which I’ve tried and get compile errors)?

When I try using variables I get a type error for the bssid as the variable type doesn’t match what the method wants, and I cant figure out how to implement the MAC address as the required variable type.

JAndrassy commented 4 months ago

so there is no issue. ok.

madmacks59 commented 4 months ago

? What ?

madmacks59 commented 4 months ago

Running a WiFI scan sketch on the ESP8266 shows the following...

13:24:46.572 -> Starting WiFi scan... 13:24:48.779 -> 4 networks found: 13:24:48.779 -> 00: [CH 03] [3C:52:A1:D4:7F:B5] -68dBm V 802.11b/g/n WPS WIFI-24 13:24:48.779 -> 01: [CH 07] [E8:9C:25:71:85:70] -31dBm V 802.11b/g/n WPS WIFI-24 13:24:48.779 -> 02: [CH 07] [42:F5:20:05:FB:DB] -68dBm V 802.11b/g ESP-05FBDB 13:24:48.779 -> 03: [CH 10] [3C:84:6A:16:D8:0E] -81dBm * V 802.11b/g/n WPS WIFI-24

FYI the ESP shown above is a different device that is connected to the "01" AP, it is not the ESP in the set up I'm working on now...

=============================================================================

In the code I've imlemented the following...

// Variable definitions

const char ssid = "WIFI-24"; const char password = "sillyPassword; const byte bssid[] = {0xE8, 0x9C, 0x25, 0x71, 0x85, 0x70};

// Down in the conncect code

bool wifiConnect() { WiFi.mode(WIFI_STA); WiFi.begin(ssid, password, 07, bssid); if (WiFi.status() == WL_CONNECTED) { delay(1000); Serial.println("Connected to Wi-Fi network"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); return true; } else { Serial.println("Wi-Fi connection failed!"); Serial.println(WiFi.status()); return false; } }

When I run the code I get... 07:45:57.655 -> Wi-Fi connection failed! 07:45:57.655 -> 7

If I change the WiFi.begin code to "WiFi.begin(ssid, password);" and rename the SSID to a unique name like "WIFI-24-X" on the "01" AP and in the code things run just fine.

So it seems to me that the issue is that the ESP is seeing three APs advertising "WIFI-24" and fails to pick the strongest signal AP.

The methond WiFi.begin() implements things as follows as far as I can tell...

Parameters:

const char ssid const char passphrase = 0 int32_t channel = 0 (optional) const uint8_t * bssid = 0 (optional) bool connect = true (optional)

So I believe my basic issue is I really don't understand how to implement the bssid as a "const uint8_t" variable, which means my definition in the above example is crap. So, that's why I'm asking for a code snippet that shows how to define the variable properly to pass to the begin() method and possibly how to use the method without needing to specifiy the channel at all as it could change on router/AP reboot...

JAndrassy commented 4 months ago

add WiFi.waitForConnectionResult() after WiFi.begin

madmacks59 commented 4 months ago

Ok...I'll give that a try. Thank you.

But...

Isn't there anyone that can actually answer the question I'm asking? What I want to learn/understand is how to implement the method as it's defined and published. The library says you should be able to pass the MAC address of the AP you want to connect with, right? But nowhere in the example code or the document is there an actual explanation of how to actually do it. Google searches, and I've done a lot of searching, doesn't turn up a single example of how these parameters can be used.

JAndrassy commented 4 months ago

you don't wait until it connected so you can't know if it connects to bssid or strongest or anything

madmacks59 commented 4 months ago

The function is actually "WiFi.waitForConnectResult()" I think...at least that's what auto complete shows...not that it makes much of a diff. But the real question is the previous one, how to implement the WiFi.begin() properly using it's defined parms...

JAndrassy commented 4 months ago

you have begin right

madmacks59 commented 4 months ago

Code is shown above. Yes... there is a WiFi.begin(). And after adding the waitFor the wait just times out (-1 returned using 2000 as the timeout). Second loop thru it does connect (using the unique ssid), so I'll play around with the timing and see if it's the radio taking a few seconds to fire up. But, still looing for the info on how to implement the bssid parm...

madmacks59 commented 4 months ago

So... There was apparently some issue with timing.... I reset the router/ap to use the redundant wifi ssid, updated my code with a few delay(500) statements, added back in the bssid definition and the full bssid begin, unplugged, waited for a minute, and plugged back in, and was surprised that things apparently work now. Anyway, below is the code that seems to be working now...

` / Gary M - Propane controller This reads three tempurature sensors and reports them via MQTT and WiFi to the MFR MQTT server. It also looks at the temp reported on sensor #1 (address 0) and if the reported temp is at or below 5 degrees celsius (41 degrees fahrenheit) it opens the main propane valve on the shed heater. It keeps the valve open until the temp reaches 10 degrees celsius (50 degrees fahrenheit). At that temp the valve is closed shuting off the heater. /

include

include

include

include

// Temp sensor wires connected to D4 (GPIO2)

define ONE_WIRE_BUS 2

// Set up oneWire to communicate with devices OneWire oneWire(ONE_WIRE_BUS); // Pass oneWire reference to Dallas Temp object DallasTemperature sensors(&oneWire); // Number of temperature devices found int numberOfDevices; // Relay connected to D2 (GPIO4) const int RELAY_PIN = 4;
// Temp values (in celsius) used to control relay float onTemp = 5.0; float hysteresis = 5.0; // Instantiate device address DeviceAddress tempDeviceAddress; // WiFi connection info (SSID, Password) const char ssid = "WiFi-24"; const char password = "dummyPassword"; const byte bssid[] = {0xE8, 0x9C, 0x25, 0x71, 0x85, 0x70}; // MQTT broker information const char mqtt_broker = "192.168.1.98"; const char topic = "house/waterPump"; const int mqtt_port = 1883; const char *client_id = "ESP8266-HousePump"; // Array of float temp values for the sensors float sensorTemp[3] = {0,0,0}; // Used to generate the MQTT message packet which looks like... // {"Topic":"house/pumpShed","Gas":"Off","Temp1":99.9,"Temp2":99.99,"Temp3":99.99} char msgTopic[26] = "{\"Topic\":\"house/pumpShed\""; char msgGas[13] = ",\"Gas\":\"Off\""; // Default is Gas Off aka relay off char msgGasOff[13] = ",\"Gas\":\"Off\""; char msgGasOn[12] = ",\"Gas\":\"On\""; char msgSen1[10] = ",\"Temp1\":"; char msgSen2[10] = ",\"Temp2\":"; char msgSen3[10] = ",\"Temp3\":"; char msgSen4[2] = "}"; char mqttTmp1[6]; char mqttTmp2[6]; char mqttTmp3[6]; char mqttMsg[80]; // Instantiate the WiFi object WiFiClient espClient; // Instantiate the MQTT object PubSubClient mqttClient(espClient);

void setup() { // Start serial port Serial.begin(9600); Serial.println("** Just Rebooted **"); // Initialie the relay pin pinMode(RELAY_PIN, OUTPUT); digitalWrite(RELAY_PIN, LOW); // Start up the sensor library sensors.begin(); // Waid a sec for sensors to start delay(1000); // Grab a count of devices on the oneWire bus numberOfDevices = sensors.getDeviceCount(); Serial.print("Locating sensor devices...Found "); Serial.print(numberOfDevices, DEC); Serial.println(" devices."); if (numberOfDevices==0) { Serial.println("Found no temperature sensors, rebooting..."); ESP.restart(); } // Loop through each device & print out address for (int i = 0; i < numberOfDevices; i++) { if (sensors.getAddress(tempDeviceAddress, i)) { Serial.print("Found device "); Serial.print(i, DEC); Serial.print(" with address: "); printAddress(tempDeviceAddress); Serial.println(); } else { Serial.print("Found ghost device at "); Serial.print(i, DEC); Serial.println(" but could not detect address. Check power and cabling"); } } mqttClient.setServer(mqtt_broker, mqtt_port); // Wait a second for the radio to fully start... delay(1000);
if (wifiConnect()) { if (mqttConnect()) { Serial.println("Initial connection to WiFi & MQTT Broker was successful..."); mqttClient.disconnect(); } } else { Serial.println("Initial connection to WiFi Failed..."); } }

void loop() { // Read and process the temp sensors sensors.requestTemperatures(); // Wait for sensor buss to reply delay(500); Serial.println("--------------------------------------------------"); // Loop through each device and print out temp data for (int i = 0; i < numberOfDevices; i++) { // Get oneWire address if (sensors.getAddress(tempDeviceAddress, i)) { // Output the device ID Serial.print("Device: "); Serial.print(i, DEC); Serial.print("\t"); // Get the Temp data for the sensor float tempC = sensors.getTempC(tempDeviceAddress); sensorTemp[i] = tempC; Serial.print("Temp C: "); Serial.print(tempC); Serial.print("\tTemp F: "); // Convert tempC to Fahrenheit and print Serial.println(DallasTemperature::toFahrenheit(tempC)); if (i == 0 ) { // If First Sensor (aka 0) if (tempC <= onTemp) { // If tempurature is equal to or lower than on temp if (!digitalRead(RELAY_PIN)) { // If relay is off turn it on digitalWrite(RELAY_PIN, HIGH); Serial.println("Relay On"); strcpy(msgGas, msgGasOn); } } else { // else if (tempC >= (onTemp + hysteresis)) { // if tempurature is equal to or greater than off temp if (digitalRead(RELAY_PIN)) { // If relay is on turn it off digitalWrite(RELAY_PIN, LOW); Serial.println("Relay Off"); strcpy(msgGas, msgGasOff); } } } } } } // If WiFi is disconnected try to reconnect if (WiFi.status() != WL_CONNECTED) { wifiConnect(); }

// Build the MQTT message if WiFi and MQTT Connected if (WiFi.status() == WL_CONNECTED) { if (mqttConnect()) { // Put together the message payload strcpy(mqttMsg, msgTopic); strcat(mqttMsg, msgGas); strcat(mqttMsg, msgSen1); dtostrf(sensorTemp[0], 5, 2, mqttTmp1); strcat(mqttMsg, mqttTmp1); strcat(mqttMsg, msgSen2); dtostrf(sensorTemp[1], 5, 2, mqttTmp2); strcat(mqttMsg, mqttTmp2); strcat(mqttMsg, msgSen3); dtostrf(sensorTemp[2], 5, 2, mqttTmp3); strcat(mqttMsg, mqttTmp3); strcat(mqttMsg, msgSen4); // Send the message if (mqttClient.publish(topic, mqttMsg, false)) { Serial.println("MQTT Msg Published..."); } else { Serial.println("MQTT Msg Failed..."); Serial.print(mqttClient.state()); } // Disconnect from MQTT Broker mqttClient.disconnect(); } } Serial.println(""); // Force print buffer out just in case // delay(3001000); // Wait 5 minute delay(301000); // Wait 30 seconds }

// function to print a device address void printAddress(DeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { if (deviceAddress[i] < 16) Serial.print("0"); Serial.print(deviceAddress[i], HEX); } }

// Get a WiFi connection but don't freak if it fails bool wifiConnect() { WiFi.mode(WIFI_STA); WiFi.begin(ssid,password,07,bssid); int chkstat = WiFi.waitForConnectResult(5000); Serial.print("Wait for Connection chkstat="); Serial.println(chkstat); Serial.printf("BSSID: %s\n", WiFi.BSSIDstr().c_str()); if (WiFi.status() == WL_CONNECTED) { delay(500); Serial.println("Connected to Wi-Fi network"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); Serial.print("SSI Strength: "); Serial.println(WiFi.RSSI()); return true; } else { Serial.println("Wi-Fi connection failed!"); Serial.println(WiFi.status()); return false; } }

// Only call if there is a WIFI connection! // Connected to MQTT but don't freak if it fails. bool mqttConnect() { if (mqttClient.connect(client_id)) { Serial.println("MQTT broker connected"); return true; } else { Serial.print("MQTT Broker connection failed!"); Serial.print(mqttClient.state()); return false;
} }

`

JAndrassy commented 4 months ago

I guess automatic connection to remembered AP was happening parallel with setup(). use some of WiFi.setPeristent(false), WiFi.setAutoReconnect(false), WiFi.erase()

madmacks59 commented 4 months ago

It appears that the issue was possibly due to timing. I'd suggest that some additional examples be added to the doco that show how to use WiFi.begin(ssid,password,channel,bssid) with various options and how to define the parameters more clearly. But that's just the opinion of a relative newbie...

madmacks59 commented 4 months ago

Dang it! I added a bit of unrelated code and now the connection is failing again, exactly as before. I'm reopening this issue again, as I guess the connect with BSSID still is funky...

madmacks59 commented 4 months ago

OK, I found some other info and this may be the issue... I'm running an ASUS RT-AX86U Pro Router and that router uses "802.11ax / WiFi 6 mode" mode as its default. The info I found suggests that WiFi 6 Mode is an issue with the ESP8266 radio, so I turned off the WiFi 6 Mode and now things seem to work reliably. So, is there an issue on the ESP8266 with WiFi 6?

madmacks59 commented 4 months ago

Apparently there is a separate ticket open around this issue. The issues has to do with the newer board cores and the solution is to revert to core 2.5.2 and recompile without some of the newer functions (like WiFi scan). I did that and the board has been processing just fine for the last two days. And with the older core I didnt need to specific the AP MAC address as the library connects to the strongest AP just fine.