Any way to check for firmware updates from a script?

I used to scrape the page https://wiki.teltonika-networks.com/view/RUTX11_Firmware_Downloads with changedetection.io to get alerted when new Firmware versions were released.

Sometime in the last few days this stopped working—because it appears Teltonika has placed the wiki site behind a Cloudflare Turnstile proxy (I understand their reasons for doing this).

It appears this info is also available via some (mostly) undocumented API endpoints.

E.g. (run on device)

# /sbin/api get /firmware/device/status
{"http_body":{"success":true,"data":{"kernel_version":"5.10.224","version":"RUTX_R_00.07.10.2","build_date":"2024-10-30 06:59:57"}},"http_code":200}

and

# /sbin/api get /firmware/device/updates/status
{"http_body":{"success":true,"data":{"device":{"version":"RUTX_R_00.07.11.3","size":"25266645"}}},"http_code":200}

…to see current/latest firmwares available. But I’d rather directly check whatever API is being called there instead of having to use a specific device (which could be down, having connectivity issues, etc) to proxy this through.

Is there any proper way to do this, or do I need to use my poor man’s Python script?

Thank you “Anonymous Person” :pray: who fixed this so that the page can be checked via automation again.

…aaaaaaaand it’s broken again. Please help.

I have written the Python script below that executes a firmware check using the on-device API. However, it only sees the “Mass Production” release track. So, if there is no workaround for the wiki being blocked by CF Turnstile, then how about a track API parameter e.g.

/firmware/device/updates/status?track=latest
/firmware/device/updates/status?track=production
import requests
import json

base_url = 'http://x.x.x.x/api'
username = 'admin'
password = 'hunter2'
cred_json = { "username": username, "password": password }

try:
	authreq = requests.post(json=cred_json, timeout=5,
		url=f"{base_url}/login")
	token = authreq.json().get("data", {}).get("token")
	auth = {"Authorization": f"Bearer {token}"}
except:
	exit(1)

try:
	local = requests.get(headers=auth, timeout=5,
		url=f"{base_url}/firmware/device/status")
	cv = local.json().get("data", {}).get("version")
	remote = requests.get(headers=auth, timeout=5,
		url=f"{base_url}/firmware/device/updates/status")
	rv = remote.json().get("data", {}).get("device").get("version")
except:
	exit(2)

if rv != 'newest':
	print(f'New firmware available: {rv} (current={cv})')
else:
	print(f'{cv} is the latest version available.')

It does get the latest version and not the “Mass Production”, though not instantly after it is released as I suspect its rolling out firmware to devices gradually and not all at once to not have a lot of issues (like most companies do).

If your seeing “Mass Production” then the issue could be that you need to install that suggested firmware first to progress to later ones.

Okay, yes I see you are right. Some days later the new firmware started getting returned by the API call.

That being said, the problem of not being able to directly query the API is still a little confusing.

My question is, why do we need to do this:

When we could just do this:

The main issue is in the top example, it relies on querying a specific hardware device to proxy the API calls. This is less reliable (the device could be offline, undergoing maintenance etc). Eliminating steps 3–5 would make the system more reliable.

Maybe you can use RMS API? I haven’t tried it but seems there is some sort of documentation https://developers.rms.teltonika-networks.com/

If not then your best bet is probably to try revere engineering the application on router itself maybe try to capture the traffic that router is sending when you call firmware version API. I see the router is using /sbin/rut_fota application to get the latest firmware version from the server. You could try adding debug option and maybe some more information will be seen /sbin/rut_fota -i -d.

Unless someone from Teltonka will answer with a better way.