Skip to content

Commit

Permalink
compressed OTA updates via esp32-flashz lib
Browse files Browse the repository at this point in the history
Signed-off-by: Emil Muratov <gpm@hotplug.ru>
  • Loading branch information
vortigont committed May 30, 2022
1 parent e7d61ab commit 4a52786
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Change Log

* compressed OTA updates via [esp32-flashz](https://github.com/vortigont/esp32-flashz) lib
* web application manifest added, ESPEM webpage could be added as a shortcut on mobile chrome
* adopted building with Arduino core >2.0.0
* UI now can detect if PZEM is disconnected or unreachable and show "err" values
+ energy offset feature
Expand Down
6 changes: 4 additions & 2 deletions espem/espem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ static const char PGdatajsontpl[] PROGMEM = "{\"age\":%llu,\"U\":%.1f,\"I\":%.2f
static const char PROGMEM PGsmpld[] = "Metrics collector disabled";
static const char PROGMEM PGdre[] = "Data read error";
static const char PROGMEM PGacao[] = "Access-Control-Allow-Origin";
static const char* PGmimetxt = "text/plain";
//static const char* PGmimehtml = "text/html; charset=utf-8";

using namespace pzmbus; // use general pzem abstractions

Expand Down Expand Up @@ -109,12 +111,12 @@ String& ESPEM::mktxtdata ( String& txtdata) {
// compat method for v 1.x cacti scripts
void ESPEM::wpmdata(AsyncWebServerRequest *request) {
if ( !tsc.getTScnt() ) {
request->send(503, FPSTR(PGmimetxt), FPSTR(PGdre) );
request->send(503, PGmimetxt, FPSTR(PGdre) );
return;
}

String data;
request->send(200, FPSTR(PGmimetxt), mktxtdata(data) );
request->send(200, PGmimetxt, mktxtdata(data) );
}


Expand Down
18 changes: 12 additions & 6 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extra_configs =
[common]
board_build.filesystem = littlefs
framework = arduino
src_build_flags =
build_src_flags =
!python flags.py
-std=gnu++14
-DUSE_FTP
Expand Down Expand Up @@ -50,9 +50,8 @@ platform = espressif32
board = wemos_d1_mini32
upload_speed = 460800
monitor_filters = esp32_exception_decoder
;build_flags =
; -DTZONE="MSK-3"
; -DCOUNTRY="ru"
build_flags =
-DCOUNTRY="ru"
lib_ignore =
ESPAsyncTCP
LITTLEFS
Expand Down Expand Up @@ -87,8 +86,8 @@ lib_deps =
build_flags =
${esp32_base.build_flags}
-DCOUNTRY="ru"
;src_build_flags =
; ${common.src_build_flags}
;build_src_flags =
; ${common.build_src_flags}
;src_build_unflags =
; ${common.src_build_unflags}

Expand Down Expand Up @@ -125,3 +124,10 @@ build_flags =
-DCOUNTRY="ru"
lib_ignore =
ESPAsyncTCP

; Over-the-air compressed update
; copy this template into user_ota.ini file and replace URL with your device adddress
;[espem_ota]
;extra_scripts = post_flashz.py
;OTA_URL = http://espem/update
;OTA_compress = true
96 changes: 96 additions & 0 deletions post_flashz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/python

#https://docs.platformio.org/en/latest/scripting/actions.html
#https://trass3r.github.io/coding/2018/12/20/advanced-platformio.html
#https://github.com/platformio/bintray-secure-ota/blob/master/publish_firmware.py

from os.path import basename
from os.path import isfile
from os.path import getsize

import subprocess
import requests
import sys,zlib
import re

Import("env", "projenv")

# access to global build environment
#print(env)

# access to project build environment (is used source files in "src" folder)
#print(projenv.Dump())

#
# Dump build environment (for debug purpose)
# print(env.Dump())
#


def pigz_compress(source, target, env):
firmware_path = str(target[0]) #.replace(".elf", ".bin")
#firmware_name = basename(firmware_path)
print("Compressing %s file..." % basename(firmware_path))
subprocess.run(["pigz", "-fzk11", firmware_path])

#def zlib_compress(source, target, env):
def zlib_compress(source):
imgfile = source
print("Compressing %s file..." % basename(imgfile))
with open(imgfile, 'rb') as img:
with open(imgfile + '.zz', 'wb') as deflated:
data = zlib.compress(img.read(), zlib.Z_BEST_COMPRESSION)
deflated.write(data)
compress_ratio = (float(getsize(imgfile)) - float(getsize(imgfile + '.zz'))) / float(getsize(imgfile)) * 100
print("Compress ratio %d%%" % compress_ratio)

def ota_upload(source, target, env):
file_path = str(source[0])
print ("Found OTA_url option, will attempt over-the-air upload")

try:
compress = env.GetProjectOption('OTA_compress')
if compress in ("yes", "true", "1"):
print("Found OTA_compress option")
zlib_compress(file_path)
if (isfile(file_path + ".zz")):
file_path += ".zz"
except:
print ("OTA_compress not found, NOT using compression")


url = env.GetProjectOption('OTA_url')

# check if we upload a firmware or FS image
imgtype = None
if (bool(re.search('firmware', file_path))):
imgtype = 'fw'
else:
imgtype = 'fs'

payload = {'img' : imgtype }
f = {'file': open(file_path, 'rb')}
req = None
try:
print("Uploading file %s to %s " % (file_path, url))
req = requests.post(url, data = payload, files=f)
req.raise_for_status()
except requests.exceptions.RequestException as e:
sys.stderr.write("Failed to upload file: %s\n" %
("%s\n%s" % (req.status_code, req.text) if req else str(e)))
env.Exit(1)

print("The firmware has been successfuly uploaded!")

# available targets, i.e. buildprog, size, upload, program, buildfs, uploadfs, uploadfsota
#buildprog is a target when ALL files are compiled and PROGRAM is ready.

# autocompress all bin images (fw and fs)
#env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", pigz_compress)

# Custom upload handler
try:
env.GetProjectOption('OTA_url')
env.Replace(UPLOADCMD=ota_upload)
except:
print ("OTA_url not found, fallback to serial flasher")

0 comments on commit 4a52786

Please sign in to comment.