first commit
This commit is contained in:
commit
fb497a9251
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Offline Unifi Controller downloader
|
||||
|
||||
## Purpose
|
||||
|
||||
If your unifi controleer do not have access to the interner os is behing the corporate proxy
|
||||
the controller is not able to download the updates for firmwares.
|
||||
|
||||
|
||||
## Solution
|
||||
|
||||
Download the firmwares and upload to the controller directory
|
||||
|
||||
|
||||
## Run
|
||||
|
||||
See `unifi-firmware-downlaod.sh`
|
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
certifi==2023.11.17
|
||||
charset-normalizer==3.3.2
|
||||
idna==3.4
|
||||
requests==2.31.0
|
||||
urllib3==2.1.0
|
23
unifi-firmware-downlaod.sh
Normal file
23
unifi-firmware-downlaod.sh
Normal file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
DIR_NAME=$(dirname $0)
|
||||
|
||||
PLATFORM=()
|
||||
PLATFORM+=('U7PG2')
|
||||
PLATFORM+=('U7MP')
|
||||
PLATFORM+=('U7EDU')
|
||||
PLATFORM+=('U7UKU')
|
||||
PLATFORM+=('U7IW')
|
||||
PLATFORM+=('U7IWP')
|
||||
PLATFORM+=('U7MSH')
|
||||
PLATFORM+=('U7LT')
|
||||
PLATFORM+=('U7LR')
|
||||
PLATFORM+=('U2O')
|
||||
PLATFORM+=('BZ2')
|
||||
PLATFORM+=('BZ2LR')
|
||||
PLATFORM+=('U5O')
|
||||
PLATFORM+=('U7P')
|
||||
|
||||
for VALUE in "${PLATFORM[@]}"; do
|
||||
${DIR_NAME}/env/bin/python ${DIR_NAME}/unifi-firmware-downlaod.py -f /var/lib/unifi/firmware -p ${VALUE}
|
||||
done
|
190
unifi-firmware-download.py
Normal file
190
unifi-firmware-download.py
Normal file
@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
|
||||
def load_json(filename):
|
||||
logging.info(f"reading json file {filename}")
|
||||
try:
|
||||
with open(filename) as f:
|
||||
data = json.load(f)
|
||||
return data
|
||||
except:
|
||||
logging.exception(f"could not read file {filename}")
|
||||
return None
|
||||
|
||||
def write_json(filename, data):
|
||||
logging.info(f"writing json file {filename}")
|
||||
try:
|
||||
with open(filename, "w") as f:
|
||||
json.dump(data, f)
|
||||
except:
|
||||
logging.exception(f"could not write file {filename}")
|
||||
|
||||
def load_firmware_meta(path):
|
||||
try:
|
||||
firmware_meta = load_json(os.path.join(path, "firmware_meta.json"))
|
||||
if firmware_meta is None:
|
||||
return []
|
||||
return firmware_meta.get('cached_firmwares', [])
|
||||
except:
|
||||
logging.exception(f"could load firmware meta")
|
||||
return []
|
||||
return firmware_meta
|
||||
|
||||
def write_firmware_meta(path, data):
|
||||
try:
|
||||
firmware_meta = {
|
||||
'cached_firmwares': data
|
||||
}
|
||||
write_json(os.path.join(path, "firmware_meta.json"), firmware_meta)
|
||||
except:
|
||||
logging.exception(f"could write firmware meta")
|
||||
|
||||
def online_firmware_check():
|
||||
try:
|
||||
resp = requests.get("https://fw-update.ubnt.com/api/firmware-newest",
|
||||
params={"filter": ["eq~~product~~unifi-firmware", "eq~~channel~~release"]})
|
||||
data = resp.json()
|
||||
return data.get("_embedded").get("firmware", [])
|
||||
except:
|
||||
logging.exception(f"could load firmware updates")
|
||||
return []
|
||||
|
||||
def online_firmware_download(url, filename):
|
||||
try:
|
||||
path = os.path.dirname(filename)
|
||||
os.makedirs(path, exist_ok=True)
|
||||
response = requests.get(url, stream=True)
|
||||
with open(filename, mode="wb") as file:
|
||||
for chunk in response.iter_content(chunk_size=10 * 1024):
|
||||
file.write(chunk)
|
||||
except:
|
||||
logging.exception(f"could not download firmware {url}")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def main(args):
|
||||
firmware_meta = load_firmware_meta(args.firmware_dir)
|
||||
firmware_latest = online_firmware_check()
|
||||
|
||||
# loop over the all available firmware
|
||||
# if found in 'meta', just add device to ther list
|
||||
# we assume, the firmware is already downloaded
|
||||
# if not found in 'meta', add ne item and download firmware
|
||||
|
||||
for firmware in firmware_latest:
|
||||
firmware_platform = firmware.get('platform')
|
||||
firmware_version = [
|
||||
str(firmware.get('version_major')),
|
||||
str(firmware.get('version_minor')),
|
||||
str(firmware.get('version_patch')),
|
||||
str(firmware.get('version_build')),
|
||||
]
|
||||
firmware_version = ".".join(firmware_version)
|
||||
|
||||
if args.platform is not None:
|
||||
if firmware_platform not in args.platform:
|
||||
continue
|
||||
|
||||
logging.info(f"processing firmware {firmware_platform}/{firmware_version}")
|
||||
|
||||
found = None
|
||||
|
||||
for meta in firmware_meta:
|
||||
# compare some values
|
||||
if meta.get('version') != firmware_version:
|
||||
continue
|
||||
if meta.get('md5') != firmware.get('md5'):
|
||||
continue
|
||||
if meta.get('size') != firmware.get('file_size'):
|
||||
continue
|
||||
# if all values match, we got our item
|
||||
found = meta
|
||||
break
|
||||
|
||||
# just add device to the list
|
||||
if found is not None:
|
||||
if firmware.get('platform') not in found.get('devices'):
|
||||
found['devices'].append(firmware.get('platform'))
|
||||
continue
|
||||
|
||||
firmware_url = firmware.get('_links', {}).get('data', {}).get('href', {})
|
||||
if firmware_url is None:
|
||||
logging.error(f"unalbe to get firmware path for {firmware_platform}/{firmware_version}")
|
||||
continue
|
||||
found = {
|
||||
'md5': firmware.get('md5'),
|
||||
'version': firmware_version,
|
||||
'size': firmware.get('file_size'),
|
||||
'path': os.path.join(firmware.get('platform'), firmware_version,firmware_url.split("/")[-1]),
|
||||
'devices': [firmware.get('platform')]
|
||||
}
|
||||
if online_firmware_download(firmware_url, os.path.join(args.firmware_dir, found['path'])):
|
||||
firmware_meta.append(found)
|
||||
|
||||
write_firmware_meta(args.firmware_dir, firmware_meta)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
format = "%(asctime)s: %(message)s"
|
||||
logging.basicConfig(format=format, level=logging.DEBUG, datefmt="%H:%M:%S")
|
||||
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-f", "--firmware-dir", type=str, required=True, help="directory with firmwares")
|
||||
parser.add_argument("-p","--platform", action='append', help='platform list to download', required=False)
|
||||
args = parser.parse_args()
|
||||
main(args)
|
||||
|
||||
'''
|
||||
{
|
||||
"md5": "6c7257dd9ee9342f376f4b140df1f9a0",
|
||||
"version": "4.3.28.11361",
|
||||
"size": 7250217,
|
||||
"path": "U7P/4.3.28.11361/a1e0-U7P-4.3.28-62a146a0d8dd4161a291a74fd562b9ce.bin",
|
||||
"devices": [
|
||||
"U7P"
|
||||
]
|
||||
}
|
||||
'''
|
||||
|
||||
'''
|
||||
{
|
||||
"channel": "release",
|
||||
"created": "2021-02-10T09:03:12Z",
|
||||
"file_size": 7252057,
|
||||
"id": "3a44dd11-6c86-45ef-8d4e-5dbb91349ea7",
|
||||
"md5": "02da6330a4cf868d02819bce4d583651",
|
||||
"sha256_checksum": "255736db010c226897c10bb32818992401aaf9b942910caafae7c08d5fab06a7",
|
||||
"platform": "BZ2",
|
||||
"product": "unifi-firmware",
|
||||
"updated": "2021-02-10T09:03:15Z",
|
||||
"version": "v4.3.28+11361",
|
||||
"version_major": 4,
|
||||
"version_minor": 3,
|
||||
"version_patch": 28,
|
||||
"version_build": "11361",
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "https://fw-update.ubnt.com/api/firmware/3a44dd11-6c86-45ef-8d4e-5dbb91349ea7"
|
||||
},
|
||||
"upload": [
|
||||
{
|
||||
"name": "data",
|
||||
"href": "https://fw-update.ubnt.com/api/firmware/3a44dd11-6c86-45ef-8d4e-5dbb91349ea7/data"
|
||||
},
|
||||
{
|
||||
"name": "changelog",
|
||||
"href": "https://fw-update.ubnt.com/api/firmware/3a44dd11-6c86-45ef-8d4e-5dbb91349ea7/changelog"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"href": "https://fw-download.ubnt.com/data/unifi-firmware/8822-BZ2-4.3.28-3a44dd116c8645ef8d4e5dbb91349ea7.bin"
|
||||
}
|
||||
}
|
||||
},
|
||||
'''
|
117
unifi-product-codes.txt
Normal file
117
unifi-product-codes.txt
Normal file
@ -0,0 +1,117 @@
|
||||
https://ubntwiki.com/products/software/unifi-controller/api#site_endpoints
|
||||
https://www.reddit.com/r/Ubiquiti/comments/kxudok/updated_list_device_codes/
|
||||
|
||||
Model Type ProductName
|
||||
----- ---- -----------
|
||||
BZ2 uap UAP
|
||||
BZ2LR uap UAP-LR
|
||||
U2HSR uap UAP-Outdoor+
|
||||
U2IW uap UAP-IW
|
||||
U2L48 uap UAP-LR
|
||||
U2Lv2 uap UAP-LRv2
|
||||
U2M uap UAP-Mini
|
||||
U2O uap UAP-Outdoor
|
||||
U2S48 uap UAP
|
||||
U2Sv2 uap UAPv2
|
||||
U5O uap UAP-Outdoor5
|
||||
U7E uap UAP-AC
|
||||
U7EDU uap UAP-AC-EDU
|
||||
U7Ev2 uap UAP-AC
|
||||
U7HD uap UAP-AC-HD
|
||||
U7SHD uap UAP-AC-SHD
|
||||
U7NHD uap UAP-nanoHD
|
||||
UFLHD uap UAP-FlexHD
|
||||
UHDIW uap UAP-IW-HD
|
||||
UAIW6 uap U6-IW
|
||||
UAE6 uap U6-Extender
|
||||
UAL6 uap U6-Lite
|
||||
UAM6 uap U6-Mesh
|
||||
UALR6 uap U6-LR-EA
|
||||
UAP6 uap U6-LR
|
||||
UALR6v2 uap U6-LR
|
||||
UALR6v3 uap U6-LR
|
||||
UCXG uap UAP-XG
|
||||
UXSDM uap UWB-XG
|
||||
UXBSDM uap UWB-XG-BK
|
||||
UCMSH uap UAP-XG-Mesh
|
||||
U7IW uap UAP-AC-IW
|
||||
U7IWP uap UAP-AC-IW-Pro
|
||||
U7MP uap UAP-AC-M-Pro
|
||||
U7LR uap UAP-AC-LR
|
||||
U7LT uap UAP-AC-Lite
|
||||
U7O uap UAP-AC-Outdoor
|
||||
U7P uap UAP-Pro
|
||||
U7MSH uap UAP-AC-M
|
||||
U7PG2 uap UAP-AC-Pro
|
||||
p2N uap PICOM2HP
|
||||
UDMB uap UAP-BeaconHD
|
||||
USF5P usw USW-Flex
|
||||
US8 usw US-8
|
||||
US8P60 usw US-8-60W
|
||||
US8P150 usw US-8-150W
|
||||
S28150 usw US-8-150W
|
||||
USC8 usw US-8
|
||||
USC8P60 usw US-8-60W
|
||||
USC8P150 usw US-8-150W
|
||||
US16P150 usw US-16-150W
|
||||
S216150 usw US-16-150W
|
||||
US24 usw US-24-G1
|
||||
US24PRO usw USW-Pro-24-PoE
|
||||
US24PRO2 usw USW-Pro-24
|
||||
US24P250 usw US-24-250W
|
||||
US24PL2 usw US-L2-24-PoE
|
||||
US24P500 usw US-24-500W
|
||||
S224250 usw US-24-250W
|
||||
S224500 usw US-24-500W
|
||||
US48 usw US-48-G1
|
||||
US48PRO usw USW-Pro-48-PoE
|
||||
US48PRO2 usw USW-Pro-48
|
||||
US48P500 usw US-48-500W
|
||||
US48PL2 usw US-L2-48-PoE
|
||||
US48P750 usw US-48-750W
|
||||
S248500 usw US-48-500W
|
||||
S248750 usw US-48-750W
|
||||
US6XG150 usw US-XG-6PoE
|
||||
USMINI usw USW-Flex-Mini
|
||||
USXG usw US-16-XG
|
||||
USC8P450 usw USW-Industrial
|
||||
UDC48X6 usw USW-Leaf
|
||||
USL8A usw UniFi Switch Aggregation
|
||||
USL8LP usw USW-Lite-8-PoE
|
||||
USL8MP usw USW-Mission-Critical
|
||||
USL16P usw USW-16-PoE
|
||||
USL16LP usw USW-Lite-16-PoE
|
||||
USL24 usw USW-24-G2
|
||||
USL48 usw USW-48-G2
|
||||
USL24P usw USW-24-PoE
|
||||
USL48P usw USW-48-PoE
|
||||
UGW3 ugw USG-3P
|
||||
UGW4 ugw USG-Pro-4
|
||||
UGWHD4 ugw USG
|
||||
UGWXG ugw USG-XG-8
|
||||
UDM udm UDM
|
||||
UDMSE udm UDM-SE
|
||||
UDMPRO udm UDM-Pro
|
||||
UP4 uph UVP-X
|
||||
UP5 uph UVP
|
||||
UP5t uph UVP-Pro
|
||||
UP7 uph UVP-Executive
|
||||
UP5c uph UVP
|
||||
UP5tc uph UVP-Pro
|
||||
UP7c uph UVP-Executive
|
||||
UCK uck UCK
|
||||
UCK-v2 uck UCK
|
||||
UCK-v3 uck UCK
|
||||
UCKG2 uck UCK-G2
|
||||
UCKP uck UCK-G2-Plus
|
||||
UASXG uas UAS-XG
|
||||
ULTE uap U-LTE
|
||||
ULTEPUS uap U-LTE-Pro
|
||||
ULTEPEU uap U-LTE-Pro
|
||||
UP1 uap USP-Plug
|
||||
UP6 uap USP-Strip
|
||||
USPPDUP usw USP - Power Distribution Unit Pro
|
||||
USPRPS usw USP-RPS
|
||||
US624P usw UniFi6 Switch 24
|
||||
UBB ubb UBB
|
||||
UXGPRO uxg UniFi NeXt-Gen Gateway PRO
|
Loading…
x
Reference in New Issue
Block a user