FreshTomato Integration for Home Assistant

As the Tomato router integration is very limited and legacy, I built a full local-polling Home Assistant integration for routers running FreshTomato firmware — no cloud, no external service, pure LAN.

What it monitors:

  • :satellite: Physical Ethernet ports — per-port link speed and duplex (e.g. 1 Gbps, Full Duplex) for WAN + LAN0–LAN3
  • :signal_strength: Both Wi-Fi radios — SSID, channel, security mode, noise floor, operating mode
  • :globe_with_meridians: WAN status — IP, gateway, connection type, uptime, DHCP lease
  • :twisted_rightwards_arrows: Bridge IPs — exposes both br0 and br1 addresses (great for WET/bridge mode routers)
  • :busts_in_silhouette: Connected devices — total, wireless, and wired client counts
  • :label: Firmware version — auto-detected from the router’s about page
  • :bar_chart: WAN bandwidth — cumulative download/upload byte counters

What you can control:

  • :mobile_phone_off: Toggle 2.4 GHz and 5 GHz radios on/off
  • :arrows_counterclockwise: Reboot the router
  • :arrows_clockwise: Renew WAN DHCP lease

Presence detection for all devices on the network (wireless + wired, configurable).

Works out of the box with routers in standard gateway mode and Wireless Ethernet Bridge (WET/repeater) mode — the integration detects the operating mode automatically and adapts accordingly.

Setup is pure UI — no YAML needed. You just need your router’s IP, credentials, and its HTTP ID token (a one-time lookup from your browser’s dev tools).

:arrow_right: GitHub: GitHub - mx5gr/ha-freshtomato: FreshTomato router integration for Home Assistant

Would love feedback from anyone else running FreshTomato — especially on non-Broadcom hardware where port mapping may differ.

Hi mx5gr,

Thanks for this integration. Just set it up and so far working w/ a Netgear r6300v2 running FreshTomato 2024.5. Was easy to get setup and working.

I run a dual wan with one of the lan ports set to a wan port. Doesn’t distinguish multiple wan. I’m also not seeing any detected connected devices by either wired or wireless. Might be related to my older version of FreshTomato?, I have been not wanting to mess up my network and have held off updating FT…

Thanks again,
Eric

Hi Eric,

Nice to hear that the integration (almost) works fine to your setup. I must admin that I am not using a multi-WAN configuration, hence I haven’t tested the integration with such a setup.

As for the connected devices, in my case, I am seeing the same devices in HA as the router is detecting.

Can you enable debug logging for the integration and send it over?

Hi mx5gr,

I noticed after playing more, it was reporting less than I thought it was for functioning entities. Things that do work: WiFi SSIDs show correct, IP addresses for br0 and br1 are correct, firmare displays correct, lan port link speeds and connect status is correct, and router model are correct.

Then when it comes to showing total connected devices, as well as wired and wireless connected devices, it shows 0 for all.

Another oddity is that toggling the switches to enable/disable wifi, they don’t actually change wifi state and they toggle back to the state they were at.

I got bold, and just updated my Freshtomato firmware to 2026.1. That did not resolve anything, it is semi functional just as it was before on 2024.5, with no changes.

I believe I captured debug output from the integration, but nothing is showing as any issues in the log.

2026-03-07 12:20:47.711 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:20:47.820 DEBUG (MainThread) [custom_components.freshtomato.coordinator] nvram firmware keys: t_build_time='FreshTomato 2026.1' os_version=None tomato_version=None
2026-03-07 12:20:47.820 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 0.168 seconds (success: True)
2026-03-07 12:21:01.062 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:21:01.091 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 1.080 seconds (success: True)
2026-03-07 12:21:10.214 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:21:11.148 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:21:11.172 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 0.076 seconds (success: True)
2026-03-07 12:21:32.769 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:21:32.816 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 0.157 seconds (success: True)
2026-03-07 12:21:40.240 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:21:43.956 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:21:43.982 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 1.163 seconds (success: True)
2026-03-07 12:22:10.314 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:22:13.716 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:22:13.742 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 0.089 seconds (success: True)
2026-03-07 12:22:40.266 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:23:10.303 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:23:40.289 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:23:45.713 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:23:45.738 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 0.085 seconds (success: True)
2026-03-07 12:24:10.312 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:24:16.704 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:24:16.728 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 1.076 seconds (success: True)
2026-03-07 12:24:29.067 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:24:29.161 DEBUG (MainThread) [custom_components.freshtomato.coordinator] nvram firmware keys: t_build_time='FreshTomato 2026.1' os_version=None tomato_version=None
2026-03-07 12:24:29.161 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 1.164 seconds (success: True)
2026-03-07 12:24:38.895 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:24:38.924 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 0.128 seconds (success: True)
2026-03-07 12:24:40.304 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:25:08.431 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:25:08.457 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 1.086 seconds (success: True)
2026-03-07 12:25:10.327 WARNING (event_thread_0) [sucks] Ping did not reach VacBot. Will retry.
2026-03-07 12:25:19.527 DEBUG (MainThread) [custom_components.freshtomato.coordinator] etherstates raw=None  eth_ports={}
2026-03-07 12:25:19.551 DEBUG (MainThread) [custom_components.freshtomato.coordinator] Finished fetching freshtomato (192.168.86.1) data in 1.089 seconds (success: True)

Thanks again

Hi Eric,

From your screen shot, “WAN Connected”/Connection Type etc information seem correct/populated, albeit only 1 WAN is recognized at the moment. Same with “Wireless Client Mode”, as I assume you are not operating the router with this enabled.

As for the client devices, in my setup the devices recognized by Fresh Tomato (http:///status-devices.asp , in your case http://192.168.86.1/status-devices.asp) are the same as the ones listed within HA.

What is happening in your setup regarding devices? In other words, how many (and of what kind - wired/wireless - devices are recognized by your router? Do you have a lot populated there, which do not appear in HA? The integration counted clients that got address from its own DHCP server.

I have just released a new version, 2023.3.2, which I’d like you to test with your setup. It includes extensive debug logging, hence when you enable debug logging to the component, I’ll have a pretty clear picture.

In this version, (hopefully) I have addressed the WiFi turn on/off issue, after extensive testing. It seems that Freshtomato’s wlradio.cgi is not behaving the way it should (it returns 200 OK but it neglects to perform the requested action), hence the alternative way, implemented in this version, (probably) addresses the issue - have a go and let me know (it took extensive testing).

Last but not least, counted connected devices now come from ARP list as well, not just from DHCP server leases exclusively.

Keep in mind to NOT enable debug logging, as the integration will quickly make it large… I have enabled extensive logging when in debug mode, deliberately, so that any troubleshooting is made easier…

Hi again mx5gr,

Thanks for the awesome support on your integration! I installed the update, restarted HomeAssistant with logging on, and it is working much better now.

Both Wan1 and Wan2 are captured, and all my network clients are found/shown (before, nothing was found). I use the Freshtomato router in front of a mesh wifi network in access point mode, so FreshTomato assigns all the IPs for everything on network by dhcp, but all clients show as connected by wired connection. It finds clients from a few different vlans and IP address blocks, so no issues there.

I did enable wireless on the FT router and connect directly wirelessly, and confirm it does properly show wireless client count.

The control of the radios turning on/off isn’t quite working right for me, but it isn’t a functionality I need, as I leave the FT router wireless off all the time and use separate wireless access point controlled separately. When flipping the switches on radios, I get an ‘unable to ssh’ sort of error.

I’m going to play with it a while before uploading the logs, so I can better figure out what does and doesn’t work yet. You are correct, it generates a ton of log data now! If there is a specific function or snip of log data you want me to provide, just let me know. But at this point, it is mostly working perfect for what I’d want out of it.

Here are some updated integration screenshots showing the functionality:

Thanks again!
Eric

regards,
Eric

Another screenshot (as new user I can’t attach multiple):

One more screenshot:

Hi Eric,

Good to know. I do not need any logs, as soon as functionality meets the expected scenario :wink:

I have deliberately let them to be very verbose, in order to assist debugging, at least before the integration reaches a more stable state, wrt code and functionality.

As for the radio buttons, I mentioned that an “alternative” method was pursued, however I did not give more explanation… As turning the WiFi interfaces & radios on/off via API is not fully supported by Fresh Tomato, I followed what is described here, which requires SSH access of HA to the FT router → toggle_radio [FreshTomato Wiki]

In order for the integration to control Radios, SSH access should be enabled on the router and HA should be able to connect to it, using the credentials supplied when setting up the integration (if the port is not forbidden by an intermediate firewall).

The integration currently displays a local message, if this connectivity is not established (there are relevant checks in the code). Furthermore, when toggling the WiFi interface switches, a minimum stale time of 30 sec is set before toggling again, as the router’s wireless driver is restarted in the meantime. If you use WiFi to connect to the router, this driver restart will (temporarily) disconnect SSH as well (since the wireless link will be re-established).

Last but not least (from your screenshots), you can safely delete unavailable/not provided entities shown, as they are leftovers from the previous integration version.