Skip to content

tinyDecoders: 433 MHz receiver with OLED display for tinySensor frames - #60

Merged
arcadien merged 148 commits into
masterfrom
feat/tiny-decoders
Nov 13, 2026
Merged

arcadien merged 148 commits into
masterfrom
feat/tiny-decoders

Conversation

@arcadien

@arcadien arcadien commented Nov 9, 2026

Copy link
Copy Markdown
Owner

New sub-project tinyDecoders/: an ATtiny84A receiver that decodes the frames tinySensors send and shows them on a 128×32 SSD1306 OLED. The tinySensor firmware is unchanged, apart from two radio IDs (see below).

Contents

  • Decoders (pure logic, host-tested by loopback through the repo encoders via OrdersToPulses, TECH-DECODE-001):
    • X10 RFXmeter (FUNC-DECODE-001)
    • Lacrosse WS7000 frame and fields (FUNC-DECODE-002/003)
    • Oregon v3 THN132N / THGN123N / BTHR918 frame and fields (FUNC-DECODE-004/005)
  • Display
    • SourceTable: last record of up to 6 sources (FUNC-DECODE-006)
    • FormatPage: two 16-character lines with a protocol+channel label and the age of the last frame (UI-DECODE-001)
    • Spleen 8x16 font, BSD-2-Clause (UI-DECODE-002)
    • Receiver loop: one page every 4 s, redrawing one changed character per poll (FUNC-DECODE-007)
  • Hardware
    • ReceiverHal build-time alias with a test double (TECH-DECODE-002)
    • Timer1 capture on PA7 (PLAT-DECODE-001)
    • SSD1306 over TinyI2C, no framebuffer (PLAT-DECODE-002)
  • Build
    • attiny84a env at 8 MHz; a post-build check fails the build past 384 B static RAM (CONF-DECODE-001)
    • CI and pre-commit cover tinyDecoders/ (CONF-DECODE-002)
  • Config: S_04 moves to Oregon channel 3 (CONF-BUILD-003) and robot to Lacrosse address FOUR (CONF-BUILD-004), so labels don't collide. Both sensors must be reflashed, and existing receivers will see them under new IDs.

Status

  • Native tests pass: tinyDecoders 42/42, firmware 82/82.
  • attiny84a build: flash 6314 / 8192 B, static RAM 323 / 384 B.
  • Not yet tested on hardware: radio capture, display, stack depth, and receiver noise.

🤖 Generated with Claude Code

arcadien and others added 30 commits November 9, 2026 16:46
Skips tinyDecoders/.pio so PlatformIO library caches are not linted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pulses

First requirement of the tinyDecoders sub-project (433 MHz receiver):
encoder output recorded by TestHal_ becomes the decoder test input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ack test helper

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… native env

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lses

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… to tinyDecoders

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…frames and resync

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four-state machine (preamble high/low, bit high/low) with +/-30 % windows,
48 bits into a 6-byte buffer, byte1/packet-type/parity checks before
publishing address and value. Pure logic, <stdint.h> only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also adds FUNC-DECODE-003: decoded measurements in integer tenths and lux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ws, corrupted frames, sync length and resync

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lses

Also req(FUNC-DECODE-005): OregonDecoder exposes measurements per device ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, pressure and lux values

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lses

Sync of at least 6 zero bits, LSB-first nibbles with 1 separators, frame
length from the type nibble, XOR and sum checks; a failing pulse is
re-checked as a sync high.

Also covers FUNC-DECODE-003: measurements exposed as integer tenths
(temperature, humidity, pressure) and lux, 0 when the type lacks them.

Requirements: FUNC-DECODE-002, FUNC-DECODE-003

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, pulse windows, corrupted frames, sync length and resync

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd pressure values, absent fields cleared

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ch radio source

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
S_02 and S_04 both sent on channel 1 (rolling codes 0x20 and 0x04), so
tinyDecoders, which labels pages by protocol and channel, would show
both as Ore1. Channel 2 stays documented for S_05.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
S_03 and robot both sent on Lacrosse address THREE, so tinyDecoders
could not tell them apart. ONE, TWO and THREE are used by devmodule,
SOLAR_TEST and S_03.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aracter lines

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…poses measurements

Bit level from the 1024 us middle pulse, >= 16 one sync run, frame
length and checksum position from the device ID (0x1D20 starts at the
last sync one), temperature tenths, humidity % and pressure hPa.

Requirements: FUNC-DECODE-004, FUNC-DECODE-005

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
12 sources is far more than needed: commercial stations handle 3
probes, 6 already covers the fleet's displayed sources.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lace update, distinct kinds, oldest replaced when full

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ps, labels, age units and glyph set

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o source

Maps Oregon, Lacrosse and X10 decoder output to a common SourceRecord
(tenths, lux, mV from X10 BCD), updates known sources in place, appends
new ones and replaces the least recently seen when the 6 slots are full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
arcadien and others added 29 commits November 12, 2026 19:53
…rHal, drops ATtiny

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, 8 on native

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tive

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Micro, ATtiny receiver dropped

ProMicroReceiverHal becomes AtmegaReceiverHal, compiled on ATmega328P and
ATmega32U4; only the ICP1 pin differs (PB0/D8 or PD4). ReceiverHal.h aliases
it on both MCUs, TestReceiverHal on native, #error otherwise. The ATtiny84a
receiver (HAL, entry point, env, TinyI2C dep, Arduino.h shim, check_size.py)
is removed; main_promicro.cpp becomes the single src/main.cpp.

Requirements: TECH-DECODE-002, PLAT-DECODE-003, PLAT-DECODE-004, PLAT-DECODE-005

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the Pro Mini 5 V / 16 MHz

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vs, promini artifact is firmware-tinydecoders

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/bit midpoint)

A weak THGN132N on the RXB6 gives short lows up to 649 µs; the RFLink
600 µs threshold dropped most of its frames.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1199 µs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; asymmetric weak-sensor frame decodes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… us midpoint)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…0 minutes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…8x16 glyph

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…start page 0-2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… DrawChar at any start page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cter side column

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nates secondaries every 2 s, centred waiting page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing text (32 glyphs)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…age, DrawChar start page, SourceTable Expire

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or 30 min, keeps order

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or 30 min, keeps first-seen order

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1306 pages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ol 0-5, Row(page) and Big() on the double

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…raws a 16x32 cell, Receiver keeps its two rows on pages 0 and 2

Requirements: TECH-DECODE-002, PLAT-DECODE-004

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gives the main value, source id and humidity or pressure

Drops the age, protocol label and two-line layout cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/pressure every 2 s, waits on an empty table, one cell per Poll

Drops the uptime, 4 s cycle and two-line row cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ssure; Receiver pages every 10 s with a waiting page

FormatPage(record, alternate, big, top, bottom) clips items to the field
widths so corrupt radio values never overflow. Receiver expires sources
before each page, alternates humidity/pressure every 2 s, draws one cell per
Poll (big 0-5, top, bottom, then the PROGMEM waiting text) and forces a full
redraw on layout switch. RFLink output unchanged.

Requirements: UI-DECODE-001, FUNC-DECODE-007

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and of 'Waiting for data'; C and s give blank glyphs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ata', drops C O h P s m

Regenerated from Spleen 2.2.0 spleen-8x16.bdf; the 26 kept glyphs are
byte-identical to the previous table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@arcadien
arcadien merged commit 47f244f into master Nov 13, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant