Commit Graph
1376 Commits
Author SHA1 Message Date
agessaman 9d115ad912 feat(observer): add dev-preview observer envs for 11 more ESP32-S3 boards
Repeater + room-server observer builds for Heltec RC32 (with and without
display), Wireless Tracker v1.0, Wireless Paper, Vision Master E213/E290,
Meshnology W12, LilyGo T-ETH Elite (WiFi only), T3S3 SX1276, Xiao S3 and
Ebyte EoRa-S3. The 4 MB boards (T3S3 SX1276, EoRa-S3) use min_spiffs and
omit SNMP; non-PSRAM boards opt into MQTT_NEIGHBORS_WITHOUT_PSRAM.
2026-09-26 10:03:48 -07:00
agessaman 7e39cac254 Merge upstream/dev into observer-firmware-dev
Picks up 35 upstream commits through 988d017a: board loop() hook,
sensor SUBSCRIBE/telemetry push, companion MyMesh::Listener UI refactor,
agc.reset.interval widened to uint16, LR1121 DC-DC, ThinkNode M4 and
Muzi Base boards, M7 companion WiFi.
2026-09-26 09:32:09 -07:00
liamcottle aa1c46e1db disable hibernate ui on 1watt wio tracker variant 2026-09-25 16:55:17 +12:00
Liam Cottle c423dece36 Merge pull request #3490 from liamcottle/fix/heltec-ct62
Fix Heltec CT62 boot loop
2026-09-23 17:48:04 +12:00
liamcottle c13b312188 fix heltec ct62 boot loop 2026-09-23 15:04:51 +12:00
Wessel Nieboer b5787757a7 Thinknode m4 - don't touch crystal and OTA name 2026-09-21 15:55:44 +02:00
Florent 8bf072a6f0 M4: Handle poweroff 2026-09-20 16:13:15 -04:00
Florent 0a15c487d8 m4: inital port 2026-09-20 15:25:18 -04:00
Liam Cottle 0886259701 Merge pull request #3108 from tjdownes/muzi-base
Add Muzi Base board support (Duo + Uno + SuperIO)
2026-09-20 22:56:32 +12:00
TJ Downes 114cf9f4fc Use the default BLE TX power on Muzi Base
Drop BLE_TX_POWER=0 from the companion envs so they use the default of
4 dBm, like most other variants. The lower power was carried over from
the original Base Duo PR and real-world range is better at the default.
2026-09-20 03:46:25 -07:00
TJ Downes 798ce636df Address review feedback on Muzi Base support
- rename the board class and files to MuziBaseBoard
- uppercase the build flags (MUZI_BASE, MUZI_BASE_SUPERIO)
- name the superIO envs muzi_base_{duo,uno}_superIO_companion_radio_ble so
  build.sh picks them up
- set MAX_CONTACTS to 350 like the other variants
- move the pin setup from initVariant() into MuziBaseBoard::begin()
2026-09-19 21:47:24 -07:00
liamcottle 4021a341f8 add wifi support to thinknode m7 ble variant 2026-09-20 15:11:21 +12:00
agessaman 854d4e2ec3 feat(thinknode-m7): make the MQTT observer envs Ethernet-preferred
Fold the CH390 overlay and NETWORK_PREFER_ETHERNET into
ThinkNode_M7_{repeater,room_server}_observer_mqtt and drop the separate
*_observer_mqtt_ethernet twins. The env names (and so the OTA manifests)
are unchanged, so existing M7 observers OTA into the Ethernet-preferred
image; without a cable they select stored Wi-Fi after a brief boot probe.
2026-09-19 10:14:23 -07:00
agessaman 8ab6a988aa Merge branch 'observer-firmware-dev' into feat/abstract-networking 2026-09-19 09:23:32 -07:00
agessaman 1b269acc02 Restore WiFi flags dropped from ThinkNode M7 companion wifi env in upstream merge
The upstream/dev merge kept our side of variants/thinknode_m7/platformio.ini,
losing -D ENABLE_WIFI_INTERFACE and +<helpers/wifi/*.cpp>. Companion WiFi is
now gated on that flag, so the env built silently without WiFi.
2026-09-19 09:10:32 -07:00
agessaman 77398bfc89 Merge upstream/dev into observer-firmware-dev 2026-09-17 21:19:23 -07:00
liamcottle cd54ee9754 add missing null display driver class for thinknode m7 ethernet variant 2026-09-17 15:52:46 +12:00
Scott Powell 3a3c13a143 * refactor to support new Board::handleCommand(), and "get/set radio.fem.*" commands 2026-09-15 18:41:11 +10:00
Scott Powell 53b6476409 Merge branch 'dev' into wio-tracker-L1-1W 2026-09-15 18:24:52 +10:00
ripplebiz 34404309ae Merge pull request #3350 from Quency-D/fix-heltec_v4r8-lna
fix-heltec_v4r8-lna
2026-09-13 12:05:35 +10:00
ripplebiz 000a1b6cda Merge pull request #3371 from agessaman/feat/tbeam-1w-thermal-fan
Add thermal fan control for T-Beam 1W
2026-09-13 12:01:37 +10:00
21cdd7b319 Add Muzi Base board support (Duo + Uno + SuperIO)
One nRF52840 variant shared across both radios, picked per env: Duo runs
the LR1121, Uno the SX1262. Same PCB, only the radio and its DIO1 pin
change.

SuperIO adds the SH1107 OLED, GPS, buzzer and joystick. GPS is driven by
the 3-position mode switch (Mode 2 = on), polled live the way thinknode_m1
does it.

Five quick user-button presses power the unit off; a press wakes it back
on (arms the button as an nRF52 GPIO SENSE source before SYSTEMOFF).

Consolidates #2054 and andyshinn's shared-base/uno work, rebased on dev.

Co-authored-by: lbibass <ewdries02@gmail.com>
Co-authored-by: Andy Shinn <andys@andyshinn.as>
2026-09-12 05:41:26 -07:00
liamcottle cee43752c7 add new ENABLE_WIFI_INTERFACE build flag for companions without providing ssid and pwd 2026-09-08 22:54:50 +12:00
Michael Graff 7c2b4d88be WiFi on/off tri-state: on when SSID set unless explicitly disabled; PicoW ships no default SSID 2026-09-06 22:18:00 -05:00
Michael Graff b11a779843 Address review: per-variant wifi src, real SSID reply, rename PicoW env 2026-09-06 21:28:04 -05:00
Michael Graff b9fa450f52 Fix review findings on Pico W WiFi/BLE 2026-09-06 20:43:37 -05:00
Michael Graff 88cc014f55 Add BLE companion support for Pico W 2026-09-06 20:15:45 -05:00
Michael Graff 0b2c47a932 Add WiFi companion support for Pico W
SerialWifiInterface has no ESP32-specific code, so move it to
helpers/wifi and reuse it on RP2040. Guard the ESP32-only WiFi
event/auto-reconnect calls and poll link state on RP2040 instead.
2026-09-05 23:15:13 -05:00
agessaman fa5ba6fa5c feat(station-g3): add second RF slot (r2) build targets
The motherboard has two RF daughterboard slots on separate GPIOs, mirrored by
its "LNA P" / "LNA S" jumpers, but the variant only ever pinned slot 1.

The shared configuration moves into [Station_G3_ESP32_common], with the SPI and
LNA lines split into per-slot sections. [Station_G3_ESP32] (slot 1) and
[Station_G3_ESP32_r2] (slot 2) each compose common + their own pins, so neither
set of -D flags has to shadow the other on the compile line - appending an
override would work only by last-wins, and esp32_base's -w hides the resulting
redefinition warning. Every pre-existing env keeps its name and resolves to
byte-identical options; verified by diffing pio project config --json-output.

PA PL1 is one board-level jumper shared by both slots, so P_PA1_EN stays in the
common section along with the TX power calibration.

Adds r2 twins of the repeater, room server and both observer envs, each an exact
mirror of its slot-1 sibling apart from the base it extends.

Slot 2 pins come from on-hardware testing in agessaman/MeshCore#49 and are not
documented publicly; the vendor wiki serves no content to fetchers.

Known limitation, unchanged from that PR: GPIO 42 and 43 fall outside the
ESP32-S3 RTC GPIO range (0-21), so the rtc_gpio_hold_en() calls in
ESP32Board::enterDeepSleep() and StationG3Board::powerOff() return
ESP_ERR_INVALID_ARG on slot 2 and the NSS and LNA pins are not latched through
deep sleep. Fixing it means gpio_hold_en() plus gpio_deep_sleep_hold_en() in
shared code.
2026-09-05 12:14:29 -07:00
agessaman 6c1f4c09a6 Fix T-Beam 1W fan races and remove PWM controls 2026-09-04 16:51:53 -07:00
agessaman 8fd6893117 feat: add T-Beam 1W thermal fan control 2026-09-04 16:03:41 -07:00
agessaman a0188bd174 fix(network): harden Ethernet-preferred lifecycle 2026-09-04 08:42:46 -07:00
agessaman fc528ae640 fix(network): set ethernet hostname before startup 2026-09-03 20:47:00 -07:00
Quency-D 7d501681bc fix-heltec_v4r8-lna 2026-09-03 17:57:09 +08:00
agessaman 366b086713 feat: add automatic network failover 2026-09-01 21:18:22 -07:00
agessaman 03c0ad81fe feat: abstract MQTT network transport 2026-09-01 16:31:28 -07:00
Liam Cottle 65aa1138ae Merge pull request #3319 from oltaco/w12_txpower
Fix Meshnology W12 TX power
2026-09-01 23:06:58 +12:00
Aleksei Mamlin 1d9a62ca4a companion: get/set timezone offset for clock
* Add tz_offset companion prefs and get/set commands for companion cli
* Use tz_offset for clock on display

Signed-off-by: Aleksei Mamlin <mamlinav@gmail.com>
2026-08-31 09:08:22 +03:00
taco e6897e8bb7 fix Meshnology W12 TX power 2026-08-29 15:22:54 +10:00
Adam Gessaman da6bab3e83 Merge upstream/dev into observer-firmware-dev 2026-08-28 19:45:59 -07:00
agessaman 4098ace5be fix(display): default the R8 portrait panels to DISPLAY_ROTATION=0
Rotation 2 was consistently upside down on the Expansion Kit V2 panel, so 0
becomes the compiled default for both portrait observer targets.

display.flip is unchanged and still defaults to off: the compiled constant
should be the correct orientation, with the setting reserved for a board
mounted the other way up. A node already carrying `display.flip 1` from
testing needs `set display.flip 0` after this.

Landscape targets are untouched - they take the driver's own DISPLAY_ROTATION
default of 3.
2026-08-28 15:45:19 -07:00
agessaman 5da46cc518 fix(display): make the USER button click immediate, 3 s hold to power off
Power-off now needs a 3 second hold; any shorter press toggles the display.
MomentaryButton reports a CLICK for any release short of its threshold, so
that single value defines both.

The button also felt unreliable - "a brief press doesn't wake it, more often
than not". MomentaryButton's multi-click detection withholds a CLICK for
MULTI_CLICK_WINDOW_MS (280 ms) after release, and folds a second press
arriving inside that window into a DOUBLE_CLICK. Since the handler only acts
on CLICK, an impatient second press produced nothing at all: press, see
nothing, press again, still nothing. Multi-click is now off for these targets,
so CLICK fires on release.

Both settings are build flags defaulted in variants/heltec_v4_r8/target.cpp
and overridden only on the two TFT observer bases, because the companion
builds share this user_btn and do use double/triple click.

DISPLAY_TOUCH_DEBUG additionally logs which input caused a toggle
("Display: button -> on"), so any remaining flake can be attributed to the
button or to a spurious touch read rather than guessed at.
2026-08-28 15:37:09 -07:00
agessaman 11d7551ccd fix(display): correct R8 touch decode, display wake and power-off
Four defects found by hardware testing of the Expansion Kit V2.

Touch never registered. The panel's controller does not use the point-count
encoding the reference CHSC6X drivers document: byte 0 reads 0x00 idle and
0x1F while a finger is down, so testing for a count of 1 never fired. A
partly-failed read leaves 0xFF, which must not count as a press either, so
the test is now != 0x00 && != 0xFF.

Touch polling could stall the UI loop for ~1 s at a time. The controller
NACKs its address whenever it has nothing to report, and calling requestFrom()
unconditionally logged a bus error on every 50 ms poll and, once the bus
wedged, burned a full ESP_ERR_TIMEOUT inside loop(). Probe the address first,
which reports the same NACK quietly, and bound the read with setTimeOut().

The display could not be woken once it blanked; only RST brought it back.
turnOn() re-ran the whole display.init(), which re-enters SPI setup, spends
~500 ms in Adafruit's reset delays and pulses GPIO 21 - the line shared with
TP_RST, so it reset the touch controller on every wake. Since turnOff() no
longer parks that line low, the panel stays configured while dark and waking
is just the backlight. Toggling also clears the refresh deadline so the
current frame is drawn immediately instead of the stale one.

Power-off rebooted instead of staying off. powerOff() went through
enterDeepSleep(), which always arms an ext1 wake on P_LORA_DIO_1; a deep-sleep
wake is a full reboot, so a node in live traffic restarted within seconds of
showing "Turning OFF". It now disables every wake source, so the node stays
down until RST or a power cycle.

Note that the display off/on cycle had never been exercised on this board
before: observer builds pinned AUTO_OFF_MILLIS=0, so the panel never blanked
until display.timeout made it a runtime setting.
2026-08-28 14:26:52 -07:00
agessaman 5d56267176 feat(display): add R8 observer TFT dashboard, touch toggle and display.timeout
Replace the sparse Heltec V4 R8 observer home screen with a padded dark
analytics dashboard, add manual display control, and make blanking a runtime
setting.

Dashboard (DISPLAY_ACTIVITY_DASHBOARD, the four R8 TFT observer envs):

- RadioActivityWindow: 20 one-minute buckets of valid RX packets, no heap.
  The caller's 32-bit millis() is extended to a monotonic 64-bit clock, so
  nothing downstream has a rollover case; an always-on node passes 2^32 ms
  after ~49.7 days, which would otherwise re-enter warm-up and divide 20
  minutes of traffic by seconds. Rates use 19 whole minutes plus the elapsed
  part of the current one rather than a fixed 1200 s.
- ObserverDashboard: header, radio strip, headline totals, a 20-bar
  packets-per-minute graph and RF/status footers, with separate portrait and
  landscape layouts. A text row is a fixed 16 px, which is 3.2 logical units
  in portrait but 4.27 in landscape, so one shared grid would overlap.
  Text is trimmed by character budget, not measured width: getTextWidth()
  reports an over-long string at the portrait driver's fallback scale, so
  DisplayDriver::drawTextEllipsized() under-trims and the row renders at half
  height.
- Six per-row signatures computed from what is actually drawn, so only the
  rows whose pixels changed repaint. No startFrame(), no whole-screen clear.
  Link state moved out of the full-frame signature, so a DHCP renewal or WiFi
  flap repaints one footer row instead of the panel.
- Dark theme by retuning the UIColor statics at runtime, which needs no
  display-driver edit and carries boot, setup, reboot and power-off with it.

Touch and button (DISPLAY_TOUCH_TOGGLE):

- CHSC6X at I2C 0x2E, polled; TP_INT is unusable (optional R13, and GPIO 43
  is U0TXD). The point-count byte is tested against a valid count, never
  against non-zero: an idle read returns 0xFF, which reads as a finger held
  down forever and latches the tap detector after one event.
- turnOff() no longer parks PIN_TFT_RST low on this board. GPIO 21 is a
  shared LCD_RST/TP_RST net, so doing that held the touch controller in
  reset for as long as the display was off. Verified against Heltec's
  expansion-board and mainboard schematics and the V4-R8 datasheet pinout,
  which also correct the pin comment in HeltecV4R8Board.cpp.
- The USER button click now toggles the display too; it previously did
  nothing whenever the display was already on.

display.timeout:

- `set display.timeout <secs>` / `get display.timeout`, 0 = stay on, 60 s
  default, 3600 max. Read live, so a change applies without a reboot and
  restarts the countdown rather than firing on the old deadline.
- Stored in MQTTPrefs (/mqtt.json), keeping NodePrefs aligned with upstream.
  Runtime-only: LegacyV1MQTTPrefs and the four frozen binary payload sizes
  are unchanged. No JSON format-version bump - the loader skips keys no
  def() claims, so older firmware reads newer files and this firmware reads
  older ones with the default applied. Both directions are covered by tests.
- Joins the observer atomic-setter contract, so a failed save rolls the live
  value back instead of only claiming to.

New periodic work uses a wrap-safe deadline check; `millis() >= deadline`
fires every loop for a whole interval before each rollover.

Adds test_radio_activity_window, test_observer_dashboard (driving the real
renderer against a recording DisplayDriver in both orientation profiles) and
test_touch_tap_detector. 440 native cases pass.
2026-08-28 13:39:16 -07:00
agessaman 0d2c926a07 feat(display): add R8 portrait observer layouts 2026-08-28 09:21:38 -07:00
agessaman c0a7cf7930 fix(boards): update Heltec V4 R8 TFT LEDA control to active HIGH 2026-08-28 07:44:16 -07:00
Liam Cottle 1c3248902a Merge pull request #3298 from meshcore-dev/companion-cli
Companion CLI
2026-08-27 18:17:10 +12:00
Scott Powell 9ab13158cb * fix for RPI Picow 2026-08-25 19:04:32 +10:00
liamcottle 7dc2d54818 add UI_NO_HIBERNATE build flag to disable hibernate screen on wio tracker l1 2026-08-24 13:45:19 +12:00
agessaman 910e6ab03d fix(boards): initialize Heltec V4 R8 TFT 2026-08-23 16:34:27 -07:00