Based off of _FailSafe's proposed configuration I managed to make it more likely to roam and easier. Works quite alright for me. At least it did last night (I reckon if WiFi generally is a bit mystical sometimes going against all odds and calculations then roaming is the black magic wizardy itself).
config usteer
# The network interface for inter-AP communication
option 'network' 'lan'
# Log messages to syslog (0/1)
option 'syslog' '1'
# Disable network communication (0/1)
option local_mode '0'
# Use IPv6 for remote exchange
option 'ipv6' '0'
# Minimum level of logged messages
# 0 = fatal
# 1 = info
# 2 = verbose
# 3 = some debug messages
# 4 = network packet information
# 5 = all debug messages
option 'debug_level' '2'
# Maximum number of neighbor reports set for a node
#option max_neighbor_reports 8
# Maximum amount of time (ms) a station may be blocked due to policy decisions
#option sta_block_timeout 30000
# Maximum amount of time (ms) a local unconnected station is tracked
#option local_sta_timeout 120000
# Maximum amount of time (ms) a measurement report is stored
#option measurement_report_timeout 120000
# Local station information update interval (ms)
#option local_sta_update 1000
# Maximum number of consecutive times a station may be blocked by policy
#option max_retry_band 5
# Maximum idle time of a station entry (ms) to be considered for policy decisions
#option seen_policy_timeout 30000
# Minimum number of stations delta between APs before load balancing policy is active
#option load_balancing_threshold 0
# Minimum number of stations delta between bands before band steering policy is active
#option band_steering_threshold 5
# Interval (ms) between sending state updates to other APs
#option remote_update_interval 1000
# Number of remote update intervals after which a remote-node is deleted
#option remote_node_timeout 10
# Allow rejecting assoc requests for steering purposes (0/1)
option assoc_steering 1
# Allow ignoring probe requests for steering purposes (0/1)
#option probe_steering 0
# Minimum signal-to-noise ratio or signal level (dBm) to allow connections
option min_connect_snr -60
# Minimum signal-to-noise ratio or signal level (dBm) to remain connected
option min_snr -70
# Timeout after which a station with snr < min_snr will be kicked
#option min_snr_kick_delay 5000
# Timeout (ms) for which a client will not be steered after rejecting a BSS-transition-request
option steer_reject_timeout 10000
# Timeout (in ms) after which a association following a disassociation is not seen
# as a roam
#option roam_process_timeout 5000
# Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger
# client scans for roaming
option roam_scan_snr -55
# Maximum number of client roaming scan trigger attempts
option roam_scan_tries 2
# Retry scanning when roam_scan_tries is exceeded after this timeout (in ms)
# In case this option is set to 0, the client is kicked instead
#option roam_scan_timeout 0
# Minimum time (ms) between client roaming scan trigger attempts
option roam_scan_interval 1000
# Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger
# forced client roaming
#option roam_trigger_snr -60
# Minimum time (ms) between client roaming trigger attempts
option roam_trigger_interval 1000
# Timeout (ms) for client roam requests. usteer will kick the client after this times out.
option roam_kick_delay 5000
# Minimum signal strength difference until AP steering policy is active
option signal_diff_threshold 10
# Initial delay (ms) before responding to probe requests (to allow other APs to see packets as well)
#option initial_connect_delay 0
# Enable kicking client on excessive channel load (0/1)
#option load_kick_enabled 0
# Minimum channel load (%) before kicking clients
#option load_kick_threshold 75
# Minimum amount of time (ms) that channel load is above threshold before starting to kick clients
#option load_kick_delay 10000
# Minimum number of connected clients before kicking based on channel load
#option load_kick_min_clients 10
# Reason code on client kick based on channel load (default: WLAN_REASON_DISASSOC_AP_BUSY)
#option load_kick_reason_code 5
# Attempting to steer clients to a higher frequency-band every n ms.
# A value of 0 disabled band-steering.
option band_steering_interval 5000
# Minimal SNR or absolute signal a device has to maintain over band_steering_interval to be
# steered to a higher frequency band
option band_steering_min_snr -70
# Interval (ms) the device is sent a link-measurement request to help assess
# the bi-directional link quality. Setting the interval to 0 disables link-measurements.
#option link_measurement_interval 30000
# Script to run after bringing up a node
#option node_up_script ''
# Message types to include in log
# Available types:
# - probe_req_accept
# - probe_req_deny
# - auth_req_accept
# - auth_req_deny
# - assoc_req_accept
# - assoc_req_deny
# - load_kick_trigger
# - load_kick_reset
# - load_kick_min_clients
# - load_kick_no_client
# - load_kick_client
# - signal_kick
list event_log_types 'signal_kick'
list event_log_types 'auth_req_accept'
list event_log_types 'auth_req_deny'
list event_log_types 'assoc_req_accept'
list event_log_types 'assoc_req_deny'
# List of SSIDs to enable steering on
list ssid_list 'My_Only_SSID_for_both_2G_and_5G'
Relevant changes are:
option band_steering_interval 5000
option band_steering_min_snr -70
In my understanding this is the minimal RSSI that the client should be able to hold for 5000ms in order to be steered from 2.4GHz to 5GHz. I set this quite low & fast as I want everything possibly on 5GHz and even -70dBm is quite usable and quick compared to 2.4GHz.
option roam_scan_snr -55
option signal_diff_threshold 10
option roam_scan_interval 1000
option roam_scan_tries 2
signal_diff_threshold should be the minimum difference in dBm that's required in order to be steered. Should work on its own IMO but I found in another thread that it requires roam_scan_snr to be non-zero (as usteer seems to use 0 values as "disabled" even if 0 should be a completely valid measurement)
So basically what I'm trying to do by these 2 lines is "start scanning for better signals at just -55dBm and if there's something better than current by just 10dBm then steer"
roam_scan_interval - trying to agitate scans very frequently, hoping it'd scan & find sooner, better, faster, more efficiently
roam_scan_tries - lowered to only 2, after which the station theoretically gets kicked. I did this hoping stations would find a better AP by then if not get kicked and find one on their own.
The latter 2 are just to make things snappier, hopefully.
option min_connect_snr -60
option min_snr -70
This is pretty easy - I don't want clients connecting with less than -60dBm and anything worse than -70dBm for persisted times should be kicked
That's pretty much it. Last night it worked flawlessly with my phone and laptop with very few exceptions "being sticky" and in those cases, unfortunately, RSSI of the "further away AP" justified this as reception was still too good. Personally battling another demon, namely so that 1 AP is able to cover a whole floor but trying to not go to the upper/lower floor. Well, that's not what WiFi thinks, not always..
Channels were chosen to be as least overlapping as possible, 25dBm / 80MHz each.
Please, do correct me! I'm here to learn and better myself and the config too!