Skip to content

Commit 6593f29

Browse files
committed
Beta v0.16.025
1 parent f79a83d commit 6593f29

5 files changed

Lines changed: 74 additions & 45 deletions

File tree

.github/workflows/release3.yml

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,56 @@ jobs:
231231
env:
232232
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
233233

234+
# ------------------------------------------------------------------
235+
# Ensure the remote directory chain exists before uploading.
236+
# See release3_beta.yml for the full explanation (issue #300): the
237+
# FTP account root is the web server root (public_html), NOT chrooted
238+
# to the firmware directory, and the old FTP-Deploy-Action can fail
239+
# silently to create missing nested directories.
240+
# ------------------------------------------------------------------
241+
- name: Ensure remote FTP directory exists
242+
env:
243+
FTP_SERVER: ${{ secrets.FTP_SERVER }}
244+
FTP_USERNAME: ${{ secrets.FTP_USER }}
245+
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
246+
REPO_NAME: ${{ github.event.repository.name }}
247+
run: |
248+
python - <<'PY'
249+
import ftplib
250+
import os
251+
from urllib.parse import urlparse
252+
253+
raw_server = os.environ["FTP_SERVER"].strip()
254+
parsed = urlparse(raw_server if "://" in raw_server else f"ftp://{raw_server}")
255+
host = parsed.hostname or raw_server
256+
port = parsed.port or 21
257+
258+
ftp = ftplib.FTP()
259+
ftp.connect(host, port, timeout=20)
260+
ftp.login(os.environ["FTP_USERNAME"], os.environ["FTP_PASSWORD"])
261+
262+
target = f"/wp-content/uploads/firmware/{os.environ['REPO_NAME']}"
263+
parts = [p for p in target.split("/") if p]
264+
path = ""
265+
for part in parts:
266+
path += "/" + part
267+
try:
268+
ftp.mkd(path)
269+
print(f"Created: {path}")
270+
except ftplib.error_perm:
271+
print(f"Already exists: {path}")
272+
273+
ftp.quit()
274+
PY
275+
234276
- name: FTP Deploy .bin files to emariete.com
235277
uses: SamKirkland/FTP-Deploy-Action@2.0.0
236278
env:
237279
FTP_SERVER: ${{ secrets.FTP_SERVER }}
238280
FTP_USERNAME: ${{ secrets.FTP_USER }}
239281
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
240282
LOCAL_DIR: ./ftp_firmware/
241-
REMOTE_DIR: /${{ github.event.repository.name }}/
283+
REMOTE_DIR: /wp-content/uploads/firmware/${{ github.event.repository.name }}/
242284
METHOD: ftp
243285
PORT: 21
244286
ARGS: --verbose

.github/workflows/release3_beta.yml

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -245,16 +245,23 @@ jobs:
245245
commit_message: "Beta v${{ steps.get_version.outputs.VERSION }} manifests"
246246

247247
# ------------------------------------------------------------------
248-
# STEP 2: Inspect the FTP account root before uploading.
249-
# This is intentionally verbose and must not print credentials. It
250-
# tells us whether the account is rooted at /public_html or already
251-
# chrooted below /public_html/wp-content/uploads/firmware.
248+
# STEP 2: Ensure the remote directory chain exists before uploading.
249+
#
250+
# Confirmed 2026-08-14 via direct FTP inspection (see issue #300):
251+
# - The FTP account root ("/") IS the web server root (public_html).
252+
# - It already contains "wp-content/uploads/firmware/CO2-Gadget/".
253+
# - REMOTE_DIR below MUST therefore repeat the full web-server path
254+
# (it is NOT chrooted to the firmware directory).
255+
# SamKirkland/FTP-Deploy-Action@2.0.0 is known to silently fail to
256+
# create missing nested directories, so we create the chain ourselves
257+
# (idempotent — ignores "already exists" errors) before the upload.
252258
# ------------------------------------------------------------------
253-
- name: Inspect FTP root and firmware directories
259+
- name: Ensure remote FTP directory exists
254260
env:
255261
FTP_SERVER: ${{ secrets.FTP_SERVER }}
256262
FTP_USERNAME: ${{ secrets.FTP_USER }}
257263
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
264+
REPO_NAME: ${{ github.event.repository.name }}
258265
run: |
259266
python - <<'PY'
260267
import ftplib
@@ -265,43 +272,28 @@ jobs:
265272
parsed = urlparse(raw_server if "://" in raw_server else f"ftp://{raw_server}")
266273
host = parsed.hostname or raw_server
267274
port = parsed.port or 21
275+
268276
ftp = ftplib.FTP()
269-
try:
270-
ftp.connect(host, port, timeout=20)
271-
ftp.login(os.environ["FTP_USERNAME"], os.environ["FTP_PASSWORD"])
272-
print(f"FTP server: {host}:{port}")
273-
print(f"FTP PWD: {ftp.pwd()}")
274-
except Exception as exc:
275-
# Diagnostics must never prevent the actual deploy action.
276-
print(f"FTP diagnostic connection failed: {type(exc).__name__}: {exc}")
277-
raise SystemExit(0)
278-
279-
candidates = [
280-
".",
281-
"/",
282-
"/public_html",
283-
"/public_html/wp-content",
284-
"/public_html/wp-content/uploads",
285-
"/public_html/wp-content/uploads/firmware",
286-
"/wp-content",
287-
"/wp-content/uploads",
288-
"/wp-content/uploads/firmware",
289-
]
290-
for path in candidates:
277+
ftp.connect(host, port, timeout=20)
278+
ftp.login(os.environ["FTP_USERNAME"], os.environ["FTP_PASSWORD"])
279+
280+
target = f"/wp-content/uploads/firmware/{os.environ['REPO_NAME']}/beta"
281+
parts = [p for p in target.split("/") if p]
282+
path = ""
283+
for part in parts:
284+
path += "/" + part
291285
try:
292-
ftp.cwd(path)
293-
names = []
294-
ftp.retrlines("NLST", names.append)
295-
print(f"FTP PATH OK: {path} -> {names[:30]}")
296-
except Exception as exc:
297-
print(f"FTP PATH MISS: {path} -> {type(exc).__name__}")
286+
ftp.mkd(path)
287+
print(f"Created: {path}")
288+
except ftplib.error_perm:
289+
print(f"Already exists: {path}")
298290
299291
ftp.quit()
300292
PY
301293
302294
# ------------------------------------------------------------------
303295
# STEP 3: Deploy .bin files to emariete.com via FTP
304-
# The account is expected to be rooted at the firmware directory.
296+
# REMOTE_DIR repeats the full web-server path (see note above).
305297
# ------------------------------------------------------------------
306298
- name: FTP upload firmware .bin files
307299
uses: SamKirkland/FTP-Deploy-Action@2.0.0
@@ -310,9 +302,7 @@ jobs:
310302
FTP_USERNAME: ${{ secrets.FTP_USER }}
311303
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
312304
LOCAL_DIR: ./ftp_firmware/beta/
313-
# FTP account root already maps to /wp-content/uploads/firmware/.
314-
# Do not repeat the web-server path here.
315-
REMOTE_DIR: /${{ github.event.repository.name }}/beta/
305+
REMOTE_DIR: /wp-content/uploads/firmware/${{ github.event.repository.name }}/beta/
316306
METHOD: ftp
317307
PORT: 21
318308
ARGS: --verbose

CHANGELOG.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,10 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
---
88

9-
## [Unreleased] — v0.16.024-beta (branch: development)
9+
## [Unreleased] — v0.16.025-beta (branch: development)
1010

1111
### Fixed
12-
- **Beta firmware deployment**: corrected the FTP destination so firmware binaries are uploaded to the same `/beta/` path referenced by the GitHub Pages manifests. (release workflow)
13-
- **FTP account root**: corrected the remote path to account for the FTP user's chroot at the firmware directory.
14-
- **FTP deployment diagnostics**: added temporary root/path inspection to the Beta workflow without exposing credentials.
15-
- **FTP diagnostics robustness**: normalize an optional `ftp://` prefix and never block deployment when inspection cannot connect.
12+
- **#300 — Beta/Release firmware deployment**: root-caused via direct FTP inspection — the FTP account root is the web server root (`public_html`), not chrooted to the firmware directory. `REMOTE_DIR` now correctly repeats the full `/wp-content/uploads/firmware/CO2-Gadget/...` path in both `release3_beta.yml` and `release3.yml`, matching the absolute URLs baked into the manifests. Added a permanent, idempotent "ensure remote directory exists" step before upload, since the FTP action used (`SamKirkland/FTP-Deploy-Action@2.0.0`) can silently fail to create missing nested directories.
1613
- **index page polling**: dashboard now respects device's `measurementInterval` instead of hardcoded 15s polling. Removed dead code (`setUpdateIntervals`, `updateMeasurementInterval`) with multiple bugs including double ms conversion and missing `clearInterval`. (`webserver/index.js`)
1714
- **savePreferences debug log**: added `WIFI_PRIVACY` guard to `/savePreferences` debug output for consistency with `printActualSettings()` and `onWifiSettingsChanged()` (`CO2_Gadget_WIFI.h:1860`)
1815
- **ESP-NOW peer MAC**: fixed web UI save of peer MAC address — local variable was shadowing the global, causing changes via preferences page to be silently discarded (`CO2_Gadget_Preferences.h:1108`)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
**CO2-Gadget** is an advanced, feature-rich firmware for ESP32-based CO₂ monitors and air quality meters. It supports a wide range of CO₂ sensors, particulate matter (PM) sensors, environmental sensors, displays (TFT, OLED, E-Ink), and communication protocols (WiFi, BLE, MQTT, ESP-NOW). Whether you're building a custom air quality monitor or flashing a commercial board, CO2-Gadget offers enterprise-grade features in a compact embedded package.
2525

26-
> **Current version:** v0.16.024-beta — `development` branch. See [CHANGELOG.md](CHANGELOG.md) for full release history.
26+
> **Current version:** v0.16.025-beta — `development` branch. See [CHANGELOG.md](CHANGELOG.md) for full release history.
2727
2828
This repository is primarily aimed at **developers and advanced users**. If you're an end user looking to install the firmware on your device, visit the [CO2 Gadget page](https://emariete.com/medidor-co2-gadget/) for pre-built binaries, one-click browser installation, and detailed guides — no compilation required.
2929

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extra_configs = platformio_extra_configs.ini
1111
[version]
1212
build_flags =
1313
-D CO2_GADGET_VERSION="\"0.16."\"
14-
-D CO2_GADGET_REV="\"024-beta\""
14+
-D CO2_GADGET_REV="\"025-beta\""
1515

1616
;****************************************************************************************
1717
;*** You can disable features by commenting the line with a semicolon at the beginning

0 commit comments

Comments
 (0)