2018-05-17 15:13:30 +01:00
|
|
|
#!/usr/bin/env python3
|
2018-10-16 13:38:09 +01:00
|
|
|
# coding=utf-8
|
2018-05-17 15:13:30 +01:00
|
|
|
"""
|
2019-10-27 11:04:08 +00:00
|
|
|
fw-server.py - firmware server for Tasmota OTA upgrade
|
2018-05-17 15:13:30 +01:00
|
|
|
|
2019-01-01 12:55:01 +00:00
|
|
|
Copyright (C) 2019 Gennaro Tortone
|
2018-05-17 15:13:30 +01:00
|
|
|
|
2018-10-16 13:38:09 +01:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2018-05-17 15:13:30 +01:00
|
|
|
|
2018-10-16 13:38:09 +01:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2018-05-17 15:13:30 +01:00
|
|
|
|
|
|
|
|
|
|
|
Requirements:
|
|
|
|
- Python3
|
|
|
|
- pip install netifaces flask
|
|
|
|
|
|
|
|
Instructions:
|
2019-10-27 11:04:08 +00:00
|
|
|
Copy Tasmota firmware binary files in 'fw' directory or
|
2018-12-17 09:49:15 +00:00
|
|
|
specify a different directory with -f parameter.
|
2019-10-27 11:04:08 +00:00
|
|
|
A set of prebuilt files can be downloaded by Tasmota release page:
|
|
|
|
https://github.com/arendst/Tasmota/releases
|
2018-05-17 15:13:30 +01:00
|
|
|
|
2019-10-27 11:04:08 +00:00
|
|
|
Configure your Tasmota device with your fw-server URL:
|
2018-05-17 15:13:30 +01:00
|
|
|
Firmware Upgrade -> Upgrade by web server
|
|
|
|
http://<ip_address>:5000/sonoff-minimal.bin
|
|
|
|
|
2018-10-16 13:38:09 +01:00
|
|
|
|
2018-05-17 15:13:30 +01:00
|
|
|
Usage:
|
2018-10-16 13:38:09 +01:00
|
|
|
./fw-server.py -d <net_iface> (default: eth0)
|
|
|
|
or
|
|
|
|
./fw-server.py -i <ip_address>
|
2018-05-17 15:13:30 +01:00
|
|
|
|
|
|
|
Example:
|
2018-10-16 13:38:09 +01:00
|
|
|
./fw-server.py -d wlan0
|
|
|
|
or
|
|
|
|
./fw-server.py -i 192.168.1.10
|
2018-05-17 15:13:30 +01:00
|
|
|
"""
|
|
|
|
|
|
|
|
import os.path
|
2018-10-16 13:38:09 +01:00
|
|
|
from optparse import OptionParser
|
2018-05-17 15:13:30 +01:00
|
|
|
from sys import exit
|
2018-10-16 13:38:09 +01:00
|
|
|
|
2018-05-17 15:13:30 +01:00
|
|
|
from flask import Flask, send_file
|
|
|
|
import netifaces as ni
|
|
|
|
|
2018-05-17 17:03:02 +01:00
|
|
|
usage = "usage: fw-server {-d | -i} arg"
|
2018-10-16 13:38:09 +01:00
|
|
|
|
2018-05-17 17:03:02 +01:00
|
|
|
parser = OptionParser(usage)
|
2018-05-17 15:13:30 +01:00
|
|
|
parser.add_option("-d", "--dev", action="store", type="string",
|
|
|
|
dest="netdev", default="eth0", help="network interface (default: eth0)")
|
2018-05-17 17:03:02 +01:00
|
|
|
parser.add_option("-i", "--ip", action="store", type="string",
|
|
|
|
dest="ip", help="IP address to bind")
|
2018-12-17 09:49:15 +00:00
|
|
|
parser.add_option("-f", "--fwdir", action="store", type="string",
|
|
|
|
dest="fwdir", help="firmware absolute path directory (default: fw/ directory)")
|
2018-05-17 15:13:30 +01:00
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
|
2018-10-16 13:38:09 +01:00
|
|
|
netip = None
|
|
|
|
|
2018-05-17 17:03:02 +01:00
|
|
|
if options.ip is None:
|
2018-10-16 13:38:09 +01:00
|
|
|
try:
|
|
|
|
netip = ni.ifaddresses(options.netdev)[ni.AF_INET][0]['addr']
|
|
|
|
except Exception as e:
|
|
|
|
print("E: network interface error - {}".format(e))
|
|
|
|
exit(1)
|
2018-05-17 17:03:02 +01:00
|
|
|
else:
|
2018-10-16 13:38:09 +01:00
|
|
|
netip = options.ip
|
|
|
|
|
2018-12-17 09:49:15 +00:00
|
|
|
if options.fwdir is None:
|
|
|
|
fwdir = os.path.dirname(os.path.realpath(__file__)) + "/fw/"
|
|
|
|
else:
|
|
|
|
if os.path.isdir(options.fwdir):
|
|
|
|
fwdir = options.fwdir
|
|
|
|
else:
|
|
|
|
print("E: directory " + options.fwdir + " not available")
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
print(" * Directory: " + fwdir)
|
2018-05-17 15:13:30 +01:00
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
2018-10-16 13:38:09 +01:00
|
|
|
|
2018-05-17 15:13:30 +01:00
|
|
|
@app.route('/<filename>')
|
|
|
|
def fw(filename):
|
2018-12-17 09:49:15 +00:00
|
|
|
if os.path.exists(fwdir + str(filename)):
|
|
|
|
return send_file(fwdir + str(filename),
|
2018-10-16 13:38:09 +01:00
|
|
|
attachment_filename=filename,
|
|
|
|
mimetype='application/octet-stream')
|
|
|
|
|
|
|
|
return "ERROR: file not found"
|
|
|
|
|
2018-05-17 15:13:30 +01:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
try:
|
|
|
|
app.run(host=netip)
|
|
|
|
except Exception as e:
|
2018-05-17 17:03:02 +01:00
|
|
|
print("E: {}".format(e))
|