146 lines
4.8 KiB
Markdown
146 lines
4.8 KiB
Markdown
# Samsung serial VFD — ESPHome component
|
||||
|
|
|
|||
|
|
An ESPHome external component for the Samsung 2-line × 20-character serial VFD
|
|||
|
|
(vacuum fluorescent display) that takes 5 V TTL serial at 9600 baud, 8N1.
|
|||
|
|
|
|||
|
|
It keeps a copy of the screen in RAM and only sends data when something
|
|||
|
|
changes. Updates overwrite the screen in place instead of clearing it first,
|
|||
|
|
so the clock doesn't flicker.
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
components/samsung_vfd/ the component (Python schema + C++)
|
|||
|
|
examples/samsung-vfd.yaml full example: clock + two Home Assistant text entities
|
|||
|
|
examples/secrets.yaml.example
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Using it from your ESPHome server
|
|||
|
|
|
|||
|
|
Add this to your device YAML. ESPHome fetches the component from git when it
|
|||
|
|
compiles.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
external_components:
|
|||
|
|
- source: github://REPO_OWNER/REPO_NAME@main
|
|||
|
|
components: [samsung_vfd]
|
|||
|
|
refresh: 1d
|
|||
|
|
|
|||
|
|
uart:
|
|||
|
|
id: uart_vfd
|
|||
|
|
tx_pin: GPIO17
|
|||
|
|
baud_rate: 9600
|
|||
|
|
|
|||
|
|
time: # needed by the component (used by samsung_vfd.printf)
|
|||
|
|
- platform: sntp
|
|||
|
|
id: sntp_time
|
|||
|
|
|
|||
|
|
samsung_vfd:
|
|||
|
|
id: vfd
|
|||
|
|
uart_id: uart_vfd
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
For a complete device, copy [examples/samsung-vfd.yaml](examples/samsung-vfd.yaml)
|
|||
|
|
into your ESPHome config folder. Add the keys from
|
|||
|
|
[examples/secrets.yaml.example](examples/secrets.yaml.example) to your
|
|||
|
|
`secrets.yaml`.
|
|||
|
|
|
|||
|
|
## Wiring
|
|||
|
|
|
|||
|
|
The component only sends to the display. The ESP32's 3.3 V output is enough for
|
|||
|
|
most 5 V TTL inputs. ESP32 GPIOs are **not** 5 V tolerant, so never connect the
|
|||
|
|
display's TX back to the ESP32 without a level shifter or divider.
|
|||
|
|
|
|||
|
|
| Display | ESP32 |
|
|||
|
|
|---------|-------|
|
|||
|
|
| RX | GPIO17 (UART TX) |
|
|||
|
|
| GND | GND |
|
|||
|
|
| 5 V | external 5 V supply |
|
|||
|
|
|
|||
|
|
The display draws more current than a dev-board regulator can comfortably
|
|||
|
|
supply. Power it from its own supply and connect the grounds together.
|
|||
|
|
|
|||
|
|
To use GPIO1 (TX0, shared with USB logging), set `tx_pin: GPIO1` and
|
|||
|
|
`logger: baud_rate: 0` so log output doesn't end up on the display. If the
|
|||
|
|
display stays blank at 3.3 V levels, add a 74HCT125 or similar level shifter.
|
|||
|
|
|
|||
|
|
## Configuration
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
samsung_vfd:
|
|||
|
|
id: vfd
|
|||
|
|
uart_id: uart_vfd
|
|||
|
|
cols: 20 # default 20 (1–80)
|
|||
|
|
rows: 2 # default 2 (1–8)
|
|||
|
|
send_newlines: false # default false; send CR LF between lines
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The UART must be 9600 baud with a `tx_pin`. The component requires a `time:`
|
|||
|
|
component in the config.
|
|||
|
|
|
|||
|
|
## Actions
|
|||
|
|
|
|||
|
|
| Action | Options |
|
|||
|
|
|--------|---------|
|
|||
|
|
| `samsung_vfd.print` | `text` (templatable). Optional `line:` (0-based) replaces one line. Without `line:`, the text is word-wrapped over the whole screen; `\n` forces a new line. Optional `centered: true`. |
|
|||
|
|
| `samsung_vfd.printf` | Shows the current time formatted with strftime, e.g. `format: "%H:%M:%S"`. Requires `time_id:`. Takes the same `line:` and `centered:` options. Does nothing until the clock has synced. |
|
|||
|
|
| `samsung_vfd.clear` | Clears the screen. |
|
|||
|
|
| `samsung_vfd.home` | Moves the cursor home. |
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
- samsung_vfd.print:
|
|||
|
|
id: vfd
|
|||
|
|
line: 0
|
|||
|
|
text: !lambda 'return "Temp " + to_string((int) id(temp).state) + " C";'
|
|||
|
|
- samsung_vfd.printf:
|
|||
|
|
id: vfd
|
|||
|
|
time_id: sntp_time
|
|||
|
|
line: 1
|
|||
|
|
centered: true
|
|||
|
|
format: "%a %d %b %H:%M"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
From a lambda you can call `id(vfd).print(...)`, `print_line(line, text, centered)`,
|
|||
|
|
`clear()`, `home()` and `line_text(line)`.
|
|||
|
|
|
|||
|
|
Text is converted to one byte per character. Accented Latin-1 letters lose
|
|||
|
|
their accent (é → e), other non-ASCII characters become `?`, and control
|
|||
|
|
characters become spaces.
|
|||
|
|
|
|||
|
|
## What the example config does
|
|||
|
|
|
|||
|
|
- On boot: clears the screen, shows `Hello World!` for 3 s, then restores line 1.
|
|||
|
|
- Bottom line: a live clock, `%a %d %b %H:%M:%S`, updated every second (SNTP,
|
|||
|
|
Europe/Amsterdam).
|
|||
|
|
- Two Home Assistant `text` entities:
|
|||
|
|
- **VFD line 1** (max 20 chars) is shown on the top line and kept across
|
|||
|
|
reboots.
|
|||
|
|
- **VFD status** (max 40 chars) shows a full-screen, word-wrapped, centred
|
|||
|
|
banner for 10 s. The clock pauses meanwhile, then line 1 and the clock come
|
|||
|
|
back.
|
|||
|
|
- Wi-Fi with a captive-portal fallback AP, OTA updates and an encrypted native
|
|||
|
|
API.
|
|||
|
|
|
|||
|
|
## Protocol
|
|||
|
|
|
|||
|
|
| Bytes | Effect |
|
|||
|
|
|-------|--------|
|
|||
|
|
| `1B 40` (`ESC @`) | init / reset |
|
|||
|
|
| `0C` | clear screen |
|
|||
|
|
| `0B` | cursor home |
|
|||
|
|
| text | printed at the cursor; wraps to the next line by itself |
|
|||
|
|
|
|||
|
|
Each update sends `0B` (home) followed by both lines, each padded to exactly
|
|||
|
|
`cols` characters.
|
|||
|
|
|
|||
|
|
## Troubleshooting
|
|||
|
|
|
|||
|
|
- **Line 2 lands on the wrong row, or text runs together:** try
|
|||
|
|
`send_newlines: true`.
|
|||
|
|
- **The screen scrolls up a line after each update:** the display scrolls as
|
|||
|
|
soon as the last cell is written. Use `cols: 19` together with
|
|||
|
|
`send_newlines: true`.
|
|||
|
|
- **A stray character appears top-left:** the display doesn't treat `0B` as
|
|||
|
|
home. Change `CMD_HOME` in
|
|||
|
|
[samsung_vfd.h](components/samsung_vfd/samsung_vfd.h).
|
|||
|
|
- **Garbled characters:** check that `uart:` is at 9600 baud and that the
|
|||
|
|
display takes 5 V TTL levels, not RS-232 levels. A real RS-232 input needs a
|
|||
|
|
MAX232 inverter.
|