From 6dd59cabb65bcc978f41ce12f549231d855226ac Mon Sep 17 00:00:00 2001 From: iscarelli Date: Wed, 10 Jun 2026 20:52:22 -0300 Subject: [PATCH] =?UTF-8?q?Revert=20"feat(balanca):=20gravar=20firmware=20?= =?UTF-8?q?da=20balan=C3=A7a=20pela=20web=20(Web=20Serial)=20=E2=80=94=20v?= =?UTF-8?q?1.37.0=20(#46)"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c064b61b530d9280b8c4f99b561634ef96b6b165. --- CHANGELOG.md | 22 ---- VERSION | 2 +- deploy/build-firmware-bin.sh | 107 ------------------- deploy/vendor-esptool.sh | 45 -------- docs/balanca-web-flash.md | 88 ---------------- routes/admin.py | 20 ---- static/esp-flash.js | 175 -------------------------------- static/esptool.js | 6 -- static/firmware/app.bin | Bin 308912 -> 0 bytes static/firmware/balanca-c3.json | 32 ------ static/firmware/boot_app0.bin | Bin 8192 -> 0 bytes static/firmware/bootloader.bin | Bin 13248 -> 0 bytes static/firmware/partitions.bin | Bin 3072 -> 0 bytes templates/admin/scale.html | 73 ------------- templates/base.html | 1 - tests/test_scale_flash.py | 56 ---------- translations.py | 52 ---------- 17 files changed, 1 insertion(+), 678 deletions(-) delete mode 100644 deploy/build-firmware-bin.sh delete mode 100644 deploy/vendor-esptool.sh delete mode 100644 docs/balanca-web-flash.md delete mode 100644 static/esp-flash.js delete mode 100644 static/esptool.js delete mode 100644 static/firmware/app.bin delete mode 100644 static/firmware/balanca-c3.json delete mode 100644 static/firmware/boot_app0.bin delete mode 100644 static/firmware/bootloader.bin delete mode 100644 static/firmware/partitions.bin delete mode 100644 templates/admin/scale.html delete mode 100644 tests/test_scale_flash.py diff --git a/CHANGELOG.md b/CHANGELOG.md index e64eec8..d39bdcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,28 +10,6 @@ Versioning follows [SemVer](https://semver.org/): **MAJOR.MINOR.PATCH** --- -## [1.37.0] — 2026-06-10 - -### Added -- **Gravação do firmware da balança pela web** (Admin → **Estação de pesagem**, - `/admin/scale`, só admin). O usuário conecta o ESP32‑C3 por USB e grava o firmware - direto do navegador via **Web Serial + esptool‑js** — irmão do gravador Niimbot (Web - Bluetooth): Chrome/Edge no computador, HTTPS (ou `localhost`), sem instalar nada. - - O firmware é compilado e gravado em **4 pedaços separados nos seus offsets** - (`bootloader 0x0 · partitions 0x8000 · boot_app0 0xe000 · app 0x10000`) — exatamente - como o `pio upload` — via `deploy/build-firmware-bin.sh`, em `static/firmware/` + - manifesto (`balanca-c3.json`), **versionados no git** e servidos como estáticos (o - deploy por clone público/`git archive` leva tudo, sem build no servidor). Pedaços - separados (não uma imagem merged única em 0x0) + `data` como **`Uint8Array`** são o - que funciona com o esptool-js — validado em hardware (ESP32‑C3 SuperMini). - - O `esptool-js` é **vendorado** (`static/esptool.js`, via `deploy/vendor-esptool.sh`, - sem CDN/runtime); o adaptador `static/esp-flash.js` baixa o `.bin` e grava em `0x0`. - **Nenhuma mudança de CSP** (Web Serial é API JS, scripts são `'self'`). Mensagens - traduzidas no servidor (EN/ES). Ver `docs/balanca-web-flash.md`. - - Escopo desta versão: **só gravação** (binário genérico, sem segredos). Provisionamento - de Wi‑Fi/URL/chave de API (firmware com Wi‑Fi + `POST /api/weigh` + handshake - serial‑JSON + fallback SoftAP) virá numa próxima versão. - ## [1.36.0] — 2026-06-10 Endurecimento de segurança a partir de um teste externo (caixa-preta). Vários diff --git a/VERSION b/VERSION index bf50e91..39fc130 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.37.0 +1.36.0 diff --git a/deploy/build-firmware-bin.sh b/deploy/build-firmware-bin.sh deleted file mode 100644 index 035c229..0000000 --- a/deploy/build-firmware-bin.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env bash -# ── build-firmware-bin.sh — gera os binários da balança p/ flash pela web ───── -# -# O gravador web (Web Serial + esptool-js, em /admin/scale) grava os MESMOS 4 -# pedaços que o `pio run -t upload` (CLI), cada um no seu offset: -# bootloader 0x0 · partitions 0x8000 · boot_app0 0xe000 · app 0x10000 -# -# IMPORTANTE: gravar os pedaços SEPARADOS (e não uma imagem "merged" única em 0x0) -# é o que funciona com o esptool-js — a imagem merged em 0x0 falha no meio -# ("Failed to write compressed data to flash after seq N"), pois o esptool-js -# erra o cálculo de endereço de bloco numa imagem única grande. O CLI grava -# separado, por isso funciona; aqui replicamos isso. -# -# Os binários + o manifesto (offsets) são gravados em static/firmware/ e VÃO -# committados no git: o deploy é por clone público + `git archive`, então o que -# está no git é o que o site serve (sem build no servidor). -# -# Uso: bash deploy/build-firmware-bin.sh -# Requisitos: PlatformIO (pio) no PATH. -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -FW_DIR="$ROOT/firmware" -ENV="balanca-c3" -CHIP="esp32c3" -BUILD_DIR="$FW_DIR/.pio/build/$ENV" -OUT_DIR="$ROOT/static/firmware" -OUT_MANIFEST="$OUT_DIR/$ENV.json" - -command -v pio >/dev/null 2>&1 || { echo "PlatformIO (pio) não encontrado no PATH." >&2; exit 1; } - -# Python que de fato roda (no Windows o python/python3 do Store é stub). -PY="" -for _c in python3 py python; do - if command -v "$_c" >/dev/null 2>&1 && "$_c" --version >/dev/null 2>&1; then PY="$_c"; break; fi -done -[ -n "$PY" ] || { echo "Python 3 necessário (python3/py/python)." >&2; exit 1; } - -echo "==> Compilando firmware ($ENV)…" -pio run -d "$FW_DIR" -e "$ENV" - -# Offsets padrão do ESP32-C3 Arduino. O boot_app0 (seletor OTA) vem do framework. -BOOTLOADER="$BUILD_DIR/bootloader.bin" -PARTITIONS="$BUILD_DIR/partitions.bin" -APP="$BUILD_DIR/firmware.bin" -for f in "$BOOTLOADER" "$PARTITIONS" "$APP"; do - [ -f "$f" ] || { echo "Faltando $f (rode o build antes)." >&2; exit 1; } -done - -# boot_app0.bin: prefere o diretório do framework SEM sufixo de versão (o ativo). -BOOT_APP0="$(ls -1 \ - "$HOME"/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin \ - "$HOME"/.platformio/packages/framework-arduinoespressif32*/tools/partitions/boot_app0.bin \ - 2>/dev/null | head -1)" -[ -n "$BOOT_APP0" ] && [ -f "$BOOT_APP0" ] || { echo "boot_app0.bin não encontrado no framework." >&2; exit 1; } - -mkdir -p "$OUT_DIR" - -echo "==> Copiando os 4 pedaços para $OUT_DIR…" -cp -f "$BOOTLOADER" "$OUT_DIR/bootloader.bin" -cp -f "$PARTITIONS" "$OUT_DIR/partitions.bin" -cp -f "$BOOT_APP0" "$OUT_DIR/boot_app0.bin" -cp -f "$APP" "$OUT_DIR/app.bin" - -# Remove a imagem merged legada (não é mais usada — o flasher grava os pedaços). -rm -f "$OUT_DIR/$ENV.bin" - -echo "==> Gerando manifesto (offsets + sha)…" -"$PY" - "$OUT_DIR" "$OUT_MANIFEST" "$CHIP" "$ROOT" <<'PYEOF' -import hashlib, json, os, subprocess, sys, datetime -out_dir, manifest, chip, root = sys.argv[1:5] -# offset → arquivo, na MESMA ordem/endereços do `pio run -t upload`. -layout = [ - ("0x0", "bootloader.bin"), - ("0x8000", "partitions.bin"), - ("0xe000", "boot_app0.bin"), - ("0x10000", "app.bin"), -] -def sha(p): - return hashlib.sha256(open(p, "rb").read()).hexdigest() -parts = [] -for off, fn in layout: - p = os.path.join(out_dir, fn) - parts.append({"offset": off, "file": fn, - "size": os.path.getsize(p), "sha256": sha(p)}) -try: - commit = subprocess.check_output( - ["git", "-C", root, "log", "-1", "--format=%h", "--", "firmware"], - text=True).strip() -except Exception: - commit = "" -m = { - "chip": chip, - "parts": parts, - # "versão" exibida = sha do app (firmware.bin); muda quando o firmware muda. - "app_sha256": next(p["sha256"] for p in parts if p["file"] == "app.bin"), - "source_commit": commit, - "built_at": datetime.datetime.now(datetime.timezone.utc) - .strftime("%Y-%m-%dT%H:%M:%SZ"), -} -json.dump(m, open(manifest, "w"), indent=2) -print(json.dumps(m, indent=2)) -PYEOF - -echo "==> OK. Pedaços + manifesto em $OUT_DIR." -echo "Revise o git diff e committe os artefatos." diff --git a/deploy/vendor-esptool.sh b/deploy/vendor-esptool.sh deleted file mode 100644 index 996f4e8..0000000 --- a/deploy/vendor-esptool.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -# ── vendor-esptool.sh — re-vendora o esptool-js (gravador Web Serial) ────────── -# -# spool-control é PÚBLICO e o servidor clona anonimamente, então o esptool-js NÃO -# pode ser baixado em deploy/runtime — é VENDORADO no repo (igual ao driver Niimbot). -# O upstream é o pacote npm `esptool-js` (Espressif), que publica um `bundle.js` -# ESM único (mesmo bundle usado pelo ESP Web Tools). -# -# Esta é a única forma deliberada e reprodutível de atualizar a cópia vendorada: -# baixa o bundle de uma VERSÃO FIXA, carimba versão/origem no topo e grava em -# static/esptool.js. Sem download em runtime/deploy e sem CDN — o que está no git é -# o que roda (preserva CSP, deploy à prova de falhas e operação offline). -# -# Uso: -# deploy/vendor-esptool.sh # versão pinada abaixo -# deploy/vendor-esptool.sh 0.6.0 # uma versão específica -# -# Depois: revise `git diff`, bump VERSION + CHANGELOG, committe, deploy. -set -euo pipefail - -ESPTOOL_VERSION="${1:-0.6.0}" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -DEST="$ROOT/static/esptool.js" -URL="https://unpkg.com/esptool-js@${ESPTOOL_VERSION}/bundle.js" -TMP="$(mktemp)" -trap 'rm -f "$TMP"' EXIT - -echo "==> Baixando esptool-js@${ESPTOOL_VERSION} de unpkg…" -curl -fsSL --max-time 60 "$URL" -o "$TMP" - -# Sanidade: precisa ser o bundle ESM com os exports que o esp-flash.js usa. -grep -q "as ESPLoader" "$TMP" || { echo "Bundle inesperado: não exporta ESPLoader." >&2; exit 1; } -grep -q "as Transport" "$TMP" || { echo "Bundle inesperado: não exporta Transport." >&2; exit 1; } - -{ - echo "// VENDORADO — esptool-js@${ESPTOOL_VERSION} (Apache-2.0), Espressif Systems." - echo "// Fonte: ${URL}" - echo "// NÃO EDITAR À MÃO — atualize via deploy/vendor-esptool.sh. Bundle ESM único" - echo "// (importado por static/esp-flash.js). Carimbado em $(date -u +%Y-%m-%dT%H:%M:%SZ)." - cat "$TMP" -} > "$DEST" - -echo "==> OK: $DEST ($(wc -c < "$DEST") bytes)" -echo "Revise o git diff e committe." diff --git a/docs/balanca-web-flash.md b/docs/balanca-web-flash.md deleted file mode 100644 index ac7506d..0000000 --- a/docs/balanca-web-flash.md +++ /dev/null @@ -1,88 +0,0 @@ -# Gravar o firmware da balança pela web - -A página **Admin → Estação de pesagem** (`/admin/scale`, só admin) grava o firmware da -balança (ESP32‑C3) direto do navegador, via **Web Serial + esptool‑js** — o irmão do -gravador Niimbot (Web Bluetooth). Sem instalar PlatformIO, sem app. - -> **Escopo atual:** só **gravação** de um binário genérico. A configuração de Wi‑Fi, URL -> e chave de API (provisionamento) virá numa próxima versão (firmware com Wi‑Fi STA + -> `POST /api/weigh` + handshake serial‑JSON; ver roadmap no fim). - -## Requisitos do usuário - -- **Chrome ou Edge no computador** (Web Serial não existe em Safari/Firefox nem em - celular). -- **Secure context:** HTTPS (produção atrás do Traefik) **ou** `http://localhost` no dev. -- A balança ligada por USB. No diálogo do navegador, escolher a porta serial da placa. - -## Como funciona - -- O firmware é compilado e gravado em **4 pedaços separados, cada um no seu offset** — - exatamente como o `pio upload`: `bootloader 0x0 · partitions 0x8000 · boot_app0 0xe000 - · app 0x10000`. Os pedaços (`bootloader.bin`, `partitions.bin`, `boot_app0.bin`, - `app.bin`) + o manifesto `static/firmware/balanca-c3.json` (offsets, sha256) ficam em - `static/firmware/`. -- **Gravar pedaços separados (e não uma imagem "merged" única em 0x0) é o que funciona - com o esptool-js.** Uma imagem única grande falha no meio (o esptool-js erra o cálculo - de endereço de bloco). Além disso, o `data` de cada pedaço é passado como **`Uint8Array`** - — passar uma "binary string" faz o pako expandir os bytes ≥ 0x80 como UTF‑8 e o stub - rejeita o bloco final com `ESP_TOO_MUCH_DATA` (0xC9). É assim que o ESP Web Tools / ESPHome - fazem. Validado em hardware (ESP32‑C3 SuperMini). -- Os artefatos são **versionados no git** e servidos como estáticos. O deploy é por clone - público + `git archive`, então **o que está no git é o que o site serve** — não há build - no servidor (preserva o deploy à prova de falhas). -- O driver `esptool-js` é **vendorado** em `static/esptool.js` (sem CDN, sem download em - runtime); o adaptador `static/esp-flash.js` importa o driver como módulo, lê o manifesto, - baixa os pedaços e grava cada um no seu offset. As mensagens visíveis são traduzidas no - servidor. - -## Atualizar o binário quando o firmware mudar - -```bash -# 1) Compila o firmware (env balanca-c3) e gera os pedaços + manifesto: -bash deploy/build-firmware-bin.sh -# → static/firmware/{bootloader,partitions,boot_app0,app}.bin + balanca-c3.json -# 2) Revise o git diff, committe os artefatos, bump VERSION + CHANGELOG. -``` - -Requer PlatformIO (`pio`) no PATH; o `esptool.py` vem com a plataforma espressif32 -(chamado via `pio pkg exec`). Offsets ESP32‑C3 Arduino: bootloader `0x0`, partições -`0x8000`, boot_app0 `0xe000`, app `0x10000`. - -## Atualizar o esptool‑js vendorado - -```bash -deploy/vendor-esptool.sh # versão pinada (0.6.0) -deploy/vendor-esptool.sh 0.6.1 # uma versão específica -``` - -Baixa o `bundle.js` (ESM único) da versão fixa para `static/esptool.js`, carimbando a -origem. Sem download em runtime/deploy. - -## Testar - -- **Local (hardware real):** rode o app em `http://localhost:5000` (secure context para - Web Serial), plugue o ESP32‑C3, abra `/admin/scale` no Chrome/Edge → **Conectar e - gravar** → confirme o boot no monitor serial (`pio device monitor -e balanca-c3`, 115200). -- **Rede / staging (sem afetar produção):** `git push` da branch e, numa **LXC separada**, - `bash /opt/spool-control/deploy/update-lxc.sh --ref ` (o script clona o repo - público no ref dado e aplica a árvore). Acesse via HTTPS e repita o flash. **Não** mexa - na LXC 117 (produção). -- **Testes automatizados:** `tests/test_scale_flash.py` cobre o gate admin, a entrega do - binário/manifesto e a presença do adaptador no HTML. - -## Notas - -- O ESP32‑C3 SuperMini usa **USB‑Serial/JTAG** nativo; o esptool‑js grava os pedaços nos - seus offsets sem precisar do botão BOOT. -- `platformio.ini` fixa `upload_port=COM23` — irrelevante para o flash web; só afeta o - `pio upload` manual. A porta real aparece no diálogo do navegador. - -## Roadmap (próxima fase — provisionamento) - -1. Firmware: Wi‑Fi STA + cliente HTTP `POST /api/weigh` + leitura de config no NVS - (`Preferences`). -2. Handshake **serial‑JSON pequeno** logo após o flash: o site envia SSID/senha + URL + - chave de API (lida de Admin → Integrações, integração `scale`) pela mesma sessão Web - Serial; o firmware grava no NVS. -3. Fallback **SoftAP captive portal** para configurar Wi‑Fi sem Web Serial. diff --git a/routes/admin.py b/routes/admin.py index bc9c357..b554680 100644 --- a/routes/admin.py +++ b/routes/admin.py @@ -212,26 +212,6 @@ def admin_settings(): ) -# ── Estação de pesagem (gravar firmware da balança pela web) ───────────────── - -def _firmware_manifest(): - """Lê static/firmware/balanca-c3.json (gerado por deploy/build-firmware-bin.sh). - Fail-safe: ausente/corrompido → {} (a página mostra o estado sem versão).""" - path = Path(app.static_folder) / "firmware" / "balanca-c3.json" - try: - return json.loads(path.read_text()) - except Exception: - return {} - - -@app.route("/admin/scale") -@admin_required -def admin_scale(): - manifest = _firmware_manifest() - manifest_url = url_for("static", filename="firmware/balanca-c3.json") - return render_template("admin/scale.html", manifest=manifest, manifest_url=manifest_url) - - # ── Atualização do sistema ─────────────────────────────────────────────────── @app.route("/admin/update") diff --git a/static/esp-flash.js b/static/esp-flash.js deleted file mode 100644 index 407fa01..0000000 --- a/static/esp-flash.js +++ /dev/null @@ -1,175 +0,0 @@ -/* ── esp-flash.js — adaptador do esptool-js para o spool-control ─────────────── - * Cola específica deste app sobre o driver genérico (static/esptool.js, vendorado - * de esptool-js@0.6.0). Grava o firmware da balança (ESP32-C3) direto do navegador - * via Web Serial — irmão do gravador Niimbot por Web Bluetooth. - * - * Requer secure context (HTTPS ou localhost) e Chrome/Edge desktop (navigator.serial). - * O binário é o MERGED em 0x0 (static/firmware/balanca-c3.bin), gerado por - * deploy/build-firmware-bin.sh. As mensagens vêm traduzidas do servidor num - * -{% endblock %} - -{% block scripts %} - -{% endblock %} diff --git a/templates/base.html b/templates/base.html index 331cd92..417f425 100644 --- a/templates/base.html +++ b/templates/base.html @@ -99,7 +99,6 @@
  • {{ _('Marcas / Logos') }}
  • {{ _('Configurações') }}
  • {{ _('Integrações') }}
  • -
  • {{ _('Estação de pesagem') }}
  • {{ _('Backup') }} diff --git a/tests/test_scale_flash.py b/tests/test_scale_flash.py deleted file mode 100644 index 57d6025..0000000 --- a/tests/test_scale_flash.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Testes da página de gravação do firmware da balança (/admin/scale). - -Cobre o gate admin, a entrega dos pedaços do firmware + manifesto (offsets), e a -presença do adaptador esp-flash.js + i18n no HTML. O flash em si é Web Serial no -navegador (não testável em pytest). O firmware é gravado em pedaços separados, cada -um no seu offset — como o `pio upload` — porque a imagem merged única falha no -esptool-js.""" -import json -from pathlib import Path - -FW_DIR = Path(__file__).resolve().parent.parent / "static" / "firmware" - - -def test_scale_page_requires_admin(app_module, viewer_client, auth_client): - # anônimo → login; viewer → 403; admin → 200. (Cliente anônimo PRÓPRIO: o fixture - # `client` é compartilhado com `auth_client`, que o logaria como admin.) - anon = app_module.app.test_client().get("/admin/scale") - assert anon.status_code == 302 and "/login" in anon.headers["Location"] - assert viewer_client.get("/admin/scale").status_code == 403 - assert auth_client.get("/admin/scale").status_code == 200 - - -def test_scale_page_has_flasher_and_i18n(auth_client): - html = auth_client.get("/admin/scale").get_data(as_text=True) - # botão com a URL do manifesto + módulo esp-flash.js + blob de i18n - assert 'id="esp-flash-btn"' in html - assert "firmware/balanca-c3.json" in html - assert "data-manifest-url" in html - assert "esp-flash.js" in html - assert 'id="esp-flash-i18n"' in html - - -def test_firmware_parts_are_served(auth_client): - # Os pedaços são estáticos/públicos (sem segredos) — o gravador baixa cada um. - manifest = json.loads((FW_DIR / "balanca-c3.json").read_text()) - for part in manifest["parts"]: - resp = auth_client.get("/static/firmware/" + part["file"]) - assert resp.status_code == 200, part["file"] - assert int(resp.headers.get("Content-Length", "0")) == part["size"] - - -def test_firmware_manifest_is_valid(): - # Gerado por deploy/build-firmware-bin.sh; o flasher lê os offsets (como o CLI). - m = json.loads((FW_DIR / "balanca-c3.json").read_text()) - assert m["chip"] == "esp32c3" - offsets = [p["offset"] for p in m["parts"]] - assert offsets == ["0x0", "0x8000", "0xe000", "0x10000"] # mesmos do pio upload - assert {p["file"] for p in m["parts"]} == { - "bootloader.bin", "partitions.bin", "boot_app0.bin", "app.bin"} - assert len(m["app_sha256"]) == 64 - - -def test_scale_page_shows_firmware_version(auth_client): - sha8 = json.loads((FW_DIR / "balanca-c3.json").read_text())["app_sha256"][:8] - html = auth_client.get("/admin/scale").get_data(as_text=True) - assert sha8 in html diff --git a/translations.py b/translations.py index ae8e4c3..826cae4 100644 --- a/translations.py +++ b/translations.py @@ -450,32 +450,6 @@ "Roxo": "Purple", "Rosa": "Pink", "Marrom": "Brown", - # ── Estação de pesagem (gravar firmware da balança) ────────────────────── - "Estação de pesagem": "Weighing station", - "Gravar firmware da balança": "Flash the scale firmware", - "Conecte a balança (ESP32-C3) por USB e grave o firmware direto do navegador — sem instalar nada. Requer Chrome ou Edge no computador.": - "Connect the scale (ESP32-C3) over USB and flash the firmware straight from the browser — no install needed. Requires Chrome or Edge on a computer.", - "Versão do firmware": "Firmware version", - "indisponível": "unavailable", - "Compilado em": "Built at", - "A gravação substitui o firmware atual da placa conectada.": - "Flashing replaces the current firmware on the connected board.", - "Conectar e gravar": "Connect and flash", - "Esta página só grava o firmware. A configuração de Wi-Fi, URL e chave de API virá numa próxima versão.": - "This page only flashes the firmware. Wi-Fi, URL and API key setup will come in a future version.", - "Use o Chrome ou o Edge no computador (Web Serial).": - "Use Chrome or Edge on a computer (Web Serial).", - "Isto vai gravar o firmware na balança conectada. Continuar?": - "This will flash the firmware onto the connected scale. Continue?", - "Conectando…": "Connecting…", - "Conectado: ": "Connected: ", - "Baixando firmware…": "Downloading firmware…", - "Gravando…": "Flashing…", - "Reiniciando a placa…": "Resetting the board…", - "Gravação concluída. A balança vai reiniciar.": "Flash complete. The scale will restart.", - "Cancelado.": "Cancelled.", - "Nenhuma porta selecionada.": "No port selected.", - "Falha: ": "Failed: ", } _ES = { @@ -928,32 +902,6 @@ "Roxo": "Morado", "Rosa": "Rosa", "Marrom": "Marrón", - # ── Estación de pesaje (grabar firmware de la balanza) ─────────────────── - "Estação de pesagem": "Estación de pesaje", - "Gravar firmware da balança": "Grabar el firmware de la balanza", - "Conecte a balança (ESP32-C3) por USB e grave o firmware direto do navegador — sem instalar nada. Requer Chrome ou Edge no computador.": - "Conecte la balanza (ESP32-C3) por USB y grabe el firmware desde el navegador — sin instalar nada. Requiere Chrome o Edge en una computadora.", - "Versão do firmware": "Versión del firmware", - "indisponível": "no disponible", - "Compilado em": "Compilado el", - "A gravação substitui o firmware atual da placa conectada.": - "La grabación reemplaza el firmware actual de la placa conectada.", - "Conectar e gravar": "Conectar y grabar", - "Esta página só grava o firmware. A configuração de Wi-Fi, URL e chave de API virá numa próxima versão.": - "Esta página solo graba el firmware. La configuración de Wi-Fi, URL y clave de API llegará en una próxima versión.", - "Use o Chrome ou o Edge no computador (Web Serial).": - "Use Chrome o Edge en una computadora (Web Serial).", - "Isto vai gravar o firmware na balança conectada. Continuar?": - "Esto grabará el firmware en la balanza conectada. ¿Continuar?", - "Conectando…": "Conectando…", - "Conectado: ": "Conectado: ", - "Baixando firmware…": "Descargando firmware…", - "Gravando…": "Grabando…", - "Reiniciando a placa…": "Reiniciando la placa…", - "Gravação concluída. A balança vai reiniciar.": "Grabación completada. La balanza se reiniciará.", - "Cancelado.": "Cancelado.", - "Nenhuma porta selecionada.": "Ninguna puerta seleccionada.", - "Falha: ": "Error: ", } # PT-BR: só os termos que mudam em relação ao texto-fonte (Spool → Rolo).