Add config capabilities
This commit is contained in:
parent
f4d951a088
commit
7f6bc4d6f9
21
config.json
Normal file
21
config.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"devices" : {
|
||||||
|
"AA:BB:CC:DD:EE:FF" : {
|
||||||
|
"role" : "ota_test",
|
||||||
|
"version" : "latest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"firmwares" : {
|
||||||
|
"ota_test" : {
|
||||||
|
"latest" : {
|
||||||
|
"filename" : "latest.bin",
|
||||||
|
"hash" : "d41d8cd98f00b204e9800998ecf8427e"
|
||||||
|
},
|
||||||
|
"backup" : {
|
||||||
|
"filename" : "backup.bin",
|
||||||
|
"hash" : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
firmwares/ota_test/latest/latest.bin
Normal file
0
firmwares/ota_test/latest/latest.bin
Normal file
|
@ -1,34 +1,72 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import hashlib
|
|
||||||
from bottle import route, run, request, HTTPResponse, response
|
from bottle import route, run, request, HTTPResponse, response
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
import pdb
|
import pdb
|
||||||
|
import os
|
||||||
|
|
||||||
updated = True
|
updated = True
|
||||||
filename = "firmware.bin"
|
filename = "firmware.bin"
|
||||||
|
|
||||||
@route('/update')
|
@route('/update')
|
||||||
def update():
|
def updateRequest():
|
||||||
#for header in request.headers.keys():
|
#for header in request.headers.keys():
|
||||||
# print("{}: {}".format(header, request.headers.get(header, "")))
|
# print("{}: {}".format(header, request.headers.get(header, "")))
|
||||||
|
|
||||||
requestor_mac = request.headers.get("X-Esp8266-Sta-Mac")
|
if not "X-Esp8266-Sta-Mac" in request.headers:
|
||||||
running_fw_md5 = request.headers.get("X-Esp8266-Sketch-Md5", "")
|
return "Hello fellow friend! Looking for updates?"
|
||||||
print("Update request from {} with fw {}".format(requestor_mac, running_fw_md5))
|
|
||||||
available_fw_md5 = md5(filename)
|
|
||||||
|
|
||||||
print("Lates firmware available is {} - ".format(available_fw_md5), end="")
|
readConfig()
|
||||||
if available_fw_md5 != running_fw_md5:
|
global config
|
||||||
print("Differs, updating…")
|
requestor_mac = request.headers.get("X-Esp8266-Sta-Mac", "")
|
||||||
response.set_header('Content-Type', 'application/octet-stream')
|
running_fw_md5 = request.headers.get("X-Esp8266-Sketch-Md5", "")
|
||||||
response.set_header('Content-Disposition', ' attachment; filename={}'.format(filename))
|
role, version, fw_filename, fw_hash = getProperties(config, requestor_mac)
|
||||||
with open(filename, "rb") as firmware:
|
if role == "" and version == "" and fw_filename == "" and fw_hash == "":
|
||||||
fw = firmware.read()
|
print("No configuration for {} found. Serving 304 - No Firmware".format(requestor_mac))
|
||||||
response.set_header('Content-Length', '{}'.format(len(fw)))
|
return nofirmware()
|
||||||
response.set_header('X-MD5', available_fw_md5)
|
|
||||||
return fw
|
print("Update request from {} with role {} (running fw hash: {}).".format(requestor_mac, role, running_fw_md5))
|
||||||
else:
|
fw_path = os.path.join("firmwares", role, version, fw_filename)
|
||||||
|
try:
|
||||||
|
latest_fw_md5 = md5(fw_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Configured firmware not found at {}".format(fw_path))
|
||||||
|
return nofirmware()
|
||||||
|
|
||||||
|
if latest_fw_md5 != fw_hash:
|
||||||
|
print("Configured hash ({}) does not match calculeted one ({})".format(fw_hash, latest_fw_md5))
|
||||||
|
return nofirmware()
|
||||||
|
|
||||||
|
print("Latest firmware for role \"{}\" is \"{}\" ({}) - ".format(role, fw_filename, latest_fw_md5), end="")
|
||||||
|
if latest_fw_md5 == running_fw_md5:
|
||||||
print("Same, skipping…")
|
print("Same, skipping…")
|
||||||
return HTTPResponse(status=304, body="")
|
return nofirmware()
|
||||||
|
|
||||||
|
print("Differs, updating…")
|
||||||
|
response.set_header('Content-Type', 'application/octet-stream')
|
||||||
|
response.set_header('Content-Disposition', ' attachment; filename={}'.format(filename))
|
||||||
|
with open(fw_path, "rb") as fw:
|
||||||
|
firmware = fw.read()
|
||||||
|
response.set_header('Content-Length', '{}'.format(len(firmware)))
|
||||||
|
response.set_header('X-MD5', latest_fw_md5)
|
||||||
|
print("Serving {} bytes to {} with role {}".format(len(firmware), requestor_mac, role))
|
||||||
|
return firmware
|
||||||
|
|
||||||
|
def getProperties(config, mac):
|
||||||
|
configured_devices = config.get("devices", {}).keys()
|
||||||
|
devices = config.get("devices", {})
|
||||||
|
firmwares = config.get("firmwares", {})
|
||||||
|
match = devices.get(mac, {"role":"", "version":""})
|
||||||
|
role = match.get("role", "")
|
||||||
|
version = match.get("version", "")
|
||||||
|
role_firmwares = firmwares.get(role, {})
|
||||||
|
firmware = role_firmwares.get(version, {})
|
||||||
|
firmware_filename = firmware.get("filename", "")
|
||||||
|
firmware_hash = firmware.get("hash", "")
|
||||||
|
return role, version, firmware_filename, firmware_hash
|
||||||
|
|
||||||
|
def nofirmware():
|
||||||
|
return HTTPResponse(status=304, body="")
|
||||||
|
|
||||||
def md5(fname):
|
def md5(fname):
|
||||||
hash_md5 = hashlib.md5()
|
hash_md5 = hashlib.md5()
|
||||||
|
@ -37,4 +75,11 @@ def md5(fname):
|
||||||
hash_md5.update(chunk)
|
hash_md5.update(chunk)
|
||||||
return hash_md5.hexdigest()
|
return hash_md5.hexdigest()
|
||||||
|
|
||||||
|
def readConfig(config_name="config.json"):
|
||||||
|
global config
|
||||||
|
config = ""
|
||||||
|
with open(config_name, "r") as conf:
|
||||||
|
config = json.loads(conf.read())
|
||||||
|
|
||||||
|
readConfig()
|
||||||
run(host='localhost', port=8080, debug=True)
|
run(host='localhost', port=8080, debug=True)
|
||||||
|
|
Loading…
Reference in a new issue