Get list of access points / SSIDs in reach

Is there a way to get a list of SSIDs of all access points that an ESP is currently “seeing”? Similar to the list of APs in reach that are listed on my mobile?

Use case:
My BEV creates a Wifi network that I cannot use directly. But I want to detect its presence to tell that the car is in the garage (and remind us that we forgot to plug it in :).

1 Like

Scan results in this sensor?

Not sure if it only updates at boot, but I suspect so as the ESP is not continually scanning.

According to the docs this sensor only exposes data of the currently connected AP. What I am looking for is a list of available (but not necessarily connected) APs.

Look at the last option:

1 Like

Oh damn, I was wrong! I had seen this sensor before but misinterpreted it’s config params. But you are right @tom_l. This sensor CAN scan for available APs! Thanks.

1 Like

The only issue is that it is unlikely that it is a continuous scan. Just a scan on boot. Which is not going to be good for this:

Yepp, true. Just tested it. The scan happens on boot and whenever the ESP looses the WIFI connection.
So the hard way to rescan would be a cyclic reboot.

But there seems to be another more elegant way, which I found in a comment to a WIFI roaming FR:

- lambda: |-
    wifi::global_wifi_component->start_scanning();

I will try that and report back.

1 Like

The lambda call works perfectly!

Unfortunately the ESP seems not to be able to scan for networks while being connected. So the moment I call the start_scanning() method the ESP logs the message Starting scan... and then disconnects. Some 20 seconds later it reconnects again and I get my new list in the sensor. I only tested this on an ESP8266. Not sure whether ESP32 could scan while holding the connection.

Overall there is not a big difference between start_scanning() and a reboot as long as you don’t use static variables or other kinds of in-memory data that would get lost on a reboot.

With this approach my task is solved. I now trigger a WIFI scan whenever the garage door closes. When the ESP reconnects it gives me the new WIFIs in range. And I can tell whether the car is now in the garage or not. Mission completed. :smiley:

I may later add some testing of the signal strength (which is transmitted with the scan results) to avoid false positives when the car is parked directly in front of the garage door. In this situation the signal still gets through but is weak, which tells me that the car is not inside.

Here is my ESP YAML fragment for reference:

text_sensor:
  - platform: wifi_info
    scan_results:
      name: "WIFIs in range"
      icon: "mdi:wifi-marker"

api:
  services:
    - service: scan_wifi
      then:
        - lambda: |-
            wifi::global_wifi_component->start_scanning();

1 Like

Then, what is the network for?
What car is it?

I think it is part of Plug and Charge / ISO 15118. But I am not sure. The car is an Aiways U5.

Can you see it on a WiFi scan? Can you ping it?

1 Like

Sure I can see it on a scan. This post is all about that.

Ping can only work when a connection is established. Not possible without any access credentials.

What do you see?
I have an Arduino sketch that scans for WiFi devices and the scan includes the MAC address. I can see where it would be easy to add MQTT to publish a boolean, true if present and false if not, that your Home Assistant could receive and turn into an entity.

Just a thought. The CANbus in the car should be able to tell you if the car is charging or what the state of the charge is, then an ESP device could publish that information over the ESPHome API. (Don’t ask me- I’ve never read the CANbus for any of my projects).

Thanks for your input and your ideas. The basic problem is already solved. ESPHome gives me a list of the form…

First WIFI SSID: -84db
Second WIFI SSID: -68db
Third WIFI SSID: -75db

So I can easily tell whether the car’s SSID is in reach and how strong it comes in ( => car standing in the garage or outside the door).

Now THAT is the way to do it. And I already started exactly that about half a year ago. I built a circuit based on an ESP and a CAN bus adapter, all driven by ESPHome. And it works beautifully in our conventional Renault. But not in the Aiways BEV. It’s on my task list til then to check the CAN in the Aiways with the scope and find the reason for the malfunction. Just didn’t find the time to do it. But you are very right: That approach would be the silver bullet!

Most EV’s have two OBD ports.
I haven’t found the Rosetta stone to know what I am looking for in the CAN bus, but what I am doing now is in each car, an ESP8266-01 running ESPHome that wakes every minute and tries to connect to my WiFi. If it connects, then device.status is “connected”, thus the car is home. I plan to build this into an OBD plug. The first ones are just a proof of concept.

1 Like

I used that in the past to get the rssi of a certain ap (“AP Test”) which is in range of the esp:

wifi:
  id: wifithing
  networks:
  - ssid: ...

sensor:
  - platform: template
    name: "${upper_devicename} AP Test RSSI"
    id: wifiscanrssi
    update_interval: never

switch:
  - platform: template
    name: "${upper_devicename} Get AP Test RSSI"
    turn_on_action:
      lambda: |-
        auto results = id(wifithing).get_scan_result() ;
        for(auto item: results){ 
          auto ssid = item.get_ssid();
          auto rssi = item.get_rssi();
          if(ssid == "AP Test"){
            id(wifiscanrssi).publish_state(rssi);
          }
        }

Guess in 2022 a template button instead of the template switch would make sense :bulb:

I tried this on a button and works great.

wifi::global_wifi_component->start_scanning()

However I’m trying to output that to a screen…
Any ideas?

I did manage to get it displaying but it’s all one text string that goes off the screen… is there a way to format it?

I used a Markdown card to format the results. I call the service in an automation once every hour.
The code in the markdown card is as follows:

{%- set networks = states('sensor.esp32_wifi_scan_results').split('\n') -%} 
The strongest network is {{ networks[0] }} 
{{ '\n' }} 
## Top 10 Networks
{{ '\n' }}
| SSID | RSSI |
|:-----|-----:|
|{%- for net in networks -%}
{% if loop.index0 < 9 %}
{%- set ssid = net.split(': ') -%}| 
| {{ ssid[0] }} | {{ssid[1] }} |
{% endif %}
{%- endfor -%}

Note that I’ve split the text sensor result into a Dict array (one element per line)
And then split again at the ': " to separate the SSID name from the signal strength RSSI
And finally I’ve printed it using markdown table formatting (all the | are important)

2 Likes

Is this in HA?
Could i apply this to esphome as a sensor?

Yes, you do this in HA. Here is the full solution for a WiFi scanner to get list of access points/SSIDs in reach of an ESP32 using ESPHome, gathered from all of the posts above:

  1. Create a text sensor to scan the WiFi (add this to your ESP32 yaml using ESPHome)
text_sensor:
  - platform: wifi_info
    scan_results:
      name: esp32 WiFi Scan Results
  1. Create a service on the ESP32 that can be called from Home Assistant Automations
    (Add this to your ESP32 yaml using ESPHome)
api:
  services:
    - service: scan_wifi
      then:
        - lambda: |-
            wifi::global_wifi_component->start_scanning();
  1. Create an automation in Home Assistant to periodically call the service
    (Add this is Home Assistant Settings → Automations & Scenes → + Create Automation
    Triggers → + Add Trigger → Time pattern trigger
    (I just put 5 in the Minutes section to run the automation every hour at 5 mins past)
    Actions → + Add Action → Service → select the service you added in step 2
    Save
    (and that’s it - you can try it out by selecting the 3 dots menu at the right of the automation and hit “Run”)
    Note that the ESP32 will go 'offline" for about 30 seconds while doing a scan
    it reconnects to your WiFi automatically.

  2. You can see the results by selecting the entity in Settings → Devices & Services → Entities
    then put your text sensor entity name in the search field.
    This shows a coloured linear graph with all the text results.

You can also see the results if you have enabled the web interface for your ESP32
by selecting Visit on the ESPHome menu in Home Assistant

  1. For a nicer format that will show the most recent result on a dashboard in Home Assistant, add a Markdown Card.
    The code in the markdown card is as follows:
{%- set networks = states('sensor.esp32_wifi_scan_results').split('\n') -%} 
The strongest network is {{ networks[0] }} 
{{ '\n' }} 
## Top 10 Networks
{{ '\n' }}
| SSID | RSSI |
|:-----|-----:|
|{%- for net in networks -%}
{% if loop.index0 < 9 %}
{%- set ssid = net.split(': ') -%}| 
| {{ ssid[0] }} | {{ssid[1] }} |
{% endif %}
{%- endfor -%}

Note that I’ve split the text sensor result into a Dict array (one element per line)
And then split again at the ': " to separate the SSID name from the signal strength RSSI
And finally I’ve printed it using markdown table formatting (all the | are important)

1 Like