Skip to content

Commit

Permalink
update from arendst
Browse files Browse the repository at this point in the history
  • Loading branch information
gemu2015 committed Jan 23, 2025
1 parent f06588c commit 4e42b2a
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 8 deletions.
15 changes: 15 additions & 0 deletions pio-tools/compress-html.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Import("env")

import sys
from pathlib import Path

base_dir = env['PROJECT_DIR']
unishox_dir = Path(base_dir, 'tools', 'unishox')
sys.path.append(str(unishox_dir.resolve()))
sys.dont_write_bytecode = True

compress_dir = __import__('compress-html-uncompressed').compress_dir

path_uncompressed = Path(base_dir, 'tasmota', 'html_uncompressed')
path_compressed = Path(base_dir, 'tasmota', 'html_compressed')
compress_dir(path_uncompressed, path_compressed)
17 changes: 10 additions & 7 deletions pio-tools/gzip-firmware.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ def map_gzip(source, target, env):
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [map_gzip])

if tasmotapiolib.is_env_set(tasmotapiolib.ENABLE_ESP32_GZ, env) or env["PIOPLATFORM"] != "espressif32":
try:
from zopfli.gzip import compress
except:
from gzip import compress
import time

gzip_level = int(env['ENV'].get('GZIP_LEVEL', 10))

def bin_gzip(source, target, env):
# create string with location and file names based on variant
bin_file = tasmotapiolib.get_final_bin_path(env)
Expand All @@ -47,8 +47,10 @@ def bin_gzip(source, target, env):
# write gzip firmware file
with open(bin_file, "rb") as fp:
with open(gzip_file, "wb") as f:
zopfli_gz = compress(fp.read())
f.write(zopfli_gz)
time_start = time.time()
gz = tasmotapiolib.compress(fp.read(), gzip_level)
time_delta = time.time() - time_start
f.write(gz)

ORG_FIRMWARE_SIZE = bin_file.stat().st_size
GZ_FIRMWARE_SIZE = gzip_file.stat().st_size
Expand All @@ -59,10 +61,11 @@ def bin_gzip(source, target, env):
)
)
else:
print(Fore.GREEN + "Compression reduced firmware size to {:.0f}% (was {} bytes, now {} bytes)".format(
print(Fore.GREEN + "Compression reduced firmware size to {:.0f}% (was {} bytes, now {} bytes, took {:.3f} seconds)".format(
(GZ_FIRMWARE_SIZE / ORG_FIRMWARE_SIZE) * 100,
ORG_FIRMWARE_SIZE,
GZ_FIRMWARE_SIZE,
time_delta,
)
)

Expand Down
74 changes: 73 additions & 1 deletion pio-tools/tasmotapiolib.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Values in .ini files override environment variables
"""
import zlib
import pathlib
import os

Expand All @@ -42,7 +43,6 @@
# This is the default output directory
OUTPUT_DIR = pathlib.Path("build_output")


def get_variant(env) -> str:
"""Get the current build variant."""
return env["PIOENV"]
Expand Down Expand Up @@ -125,3 +125,75 @@ def is_env_set(name: str, env):
val = val.strip()
return val == "1"
return False

def _compress_with_gzip(data, level=9):
import zlib
if level < 0: level = 0
elif level > 9: level = 9
# gzip header without timestamp
zobj = zlib.compressobj(level=level, wbits=16 + zlib.MAX_WBITS)
return zobj.compress(data) + zobj.flush()

try:
import zopfli

# two python modules call themselves `zopfli`, which one is this?
if hasattr(zopfli, 'ZopfliCompressor'):
# we seem to have zopflipy
from zopfli import ZopfliCompressor, ZOPFLI_FORMAT_GZIP
def _compress_with_zopfli(data, iterations=15, maxsplit=15, **kw):
zobj = ZopfliCompressor(
ZOPFLI_FORMAT_GZIP,
iterations=iterations,
block_splitting_max=maxsplit,
**kw,
)
return zobj.compress(data) + zobj.flush()

else:
# we seem to have pyzopfli
import zopfli.gzip
def _compress_with_zopfli(data, iterations=15, maxsplit=15, **kw):
return zopfli.gzip.compress(
data,
numiterations=iterations,
blocksplittingmax=maxsplit,
**kw,
)

# values based on limited manual testing
def _level_to_params(level):
if level == 10: return (15, 15)
elif level == 11: return (15, 20)
elif level == 12: return (15, 25)
elif level == 13: return (15, 30)
elif level == 14: return (15, 35)
elif level == 15: return (33, 40)
elif level == 16: return (67, 45)
elif level == 17: return (100, 50)
elif level == 18: return (500, 100)
elif level >= 19: return (2500, 250)
else:
raise ValueError(f'Invalid level: {repr(level)}')

def compress(data, level=None, *, iterations=None, maxsplit=None, **kw):
if level is not None and (iterations is not None or maxsplit is not None):
raise ValueError("The `level` argument can't be used with `iterations` and/or `maxsplit`!")

# set parameters based on level or to defaults
if iterations is None and maxsplit is None:
if level is None: level = 10
elif level < 10: return _compress_with_gzip(data, level)
iterations, maxsplit = _level_to_params(level)

if maxsplit is not None:
kw['maxsplit'] = maxsplit

if iterations is not None:
kw['iterations'] = iterations

return _compress_with_zopfli(data, **kw)

except ModuleNotFoundError:
def compress(data, level=9, **kw):
return _compress_with_gzip(data, level)

0 comments on commit 4e42b2a

Please sign in to comment.