Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 10 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,10 @@ ln -s ~/matrix_display/matrix_display ~/.local/bin/matrix_display

Make sure `~/.local/bin` is on your `PATH`.

3. Create a `~/.matrix_display` config file:

```toml
[[display]]
target_display = "maksim"
controller_ip = "192.168.1.201"

[[display]]
target_display = "meeting_room"
controller_ip = "192.168.1.202"
```

4. Send a message:
3. Send a message:

```sh
echo "Some message" | matrix_display --target maksim
echo "Some message" | matrix_display --target 192.168.1.201
```

## Usage
Expand All @@ -73,17 +61,17 @@ If you prefer not to install anything, this also works:
PYTHONPATH=src python3 -m matrix_display
```

Use `--target` or `-t` to select which configured display to send to:
Use `--target` or `-t` to specify the controller IP or hostname:

```sh
some_command | matrix_display --target maksim
some_command | matrix_display -t maksim
some_command | matrix_display --target 192.168.1.201
some_command | matrix_display -t my-display.local
```

ANSI color sequences in stdin are supported. For example:

```sh
printf '\033[31mRED \033[32mGREEN\033[0m\n' | matrix_display -t maksim
printf '\033[31mRED \033[32mGREEN\033[0m\n' | matrix_display -t 192.168.1.201
```

## Example Usage
Expand All @@ -94,7 +82,7 @@ Display the current time in 24-hour format once a second:
#!/bin/sh

while true; do
date '+%H:%M:%S' | matrix_display -t maksim
date '+%H:%M:%S' | matrix_display -t 192.168.1.201
sleep 1
done
```
Expand All @@ -105,9 +93,9 @@ Watch the latest GitHub Actions run and display a green or red result when it fi
#!/usr/bin/env bash

if gh run watch --exit-status; then
printf '\033[32mPASSED\033[0m\n' | matrix_display -t maksim
printf '\033[32mPASSED\033[0m\n' | matrix_display -t 192.168.1.201
else
printf '\033[31mFAILED\033[0m\n' | matrix_display -t maksim
printf '\033[31mFAILED\033[0m\n' | matrix_display -t 192.168.1.201
fi
```

Expand All @@ -120,7 +108,7 @@ the scroll has finished:
text=$(printf 'ZUBAX %.0s' $(seq 1 100))

while true; do
printf '\033[31m%s\033[0m\n' "$text" | matrix_display -t maksim
printf '\033[31m%s\033[0m\n' "$text" | matrix_display -t 192.168.1.201
sleep 2m
done
```
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ name = "matrix-display"
version = "0.1.0"
description = "Art-Net controller for a 10x118 LED matrix display"
readme = "README.md"
requires-python = ">=3.12"
requires-python = ">=3.10"
dependencies = []

[project.scripts]
matrix_display = "matrix_display.cli:main"
Expand Down
12 changes: 2 additions & 10 deletions src/matrix_display/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
import math
import sys
import time
from pathlib import Path
from typing import Callable, TextIO

from .config import DEFAULT_CONFIG_PATH, resolve_controller_ip
from .led_controller import LedController
from .rendering import normalize_input_text, render_message

Expand All @@ -30,7 +28,7 @@ def main(

try:
message = _read_message(stdin or sys.stdin)
controller_ip = resolve_controller_ip(args.target, config_path=args.config)
controller_ip = args.target
rendered = render_message(message)
controller = controller_factory(target_ip=controller_ip)
frame_interval = 1 / getattr(controller, "fps", 30)
Expand Down Expand Up @@ -64,13 +62,7 @@ def _build_parser() -> argparse.ArgumentParser:
"-t",
"--target",
required=True,
help="Named target display from ~/.matrix_display.",
)
parser.add_argument(
"--config",
type=Path,
default=DEFAULT_CONFIG_PATH,
help=f"Path to the TOML config file (default: {DEFAULT_CONFIG_PATH}).",
help="IP address or hostname of the PixLite controller.",
)
return parser

Expand Down
105 changes: 0 additions & 105 deletions src/matrix_display/config.py

This file was deleted.

100 changes: 25 additions & 75 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
from __future__ import annotations

import io
import tempfile
import unittest
from pathlib import Path

from matrix_display.cli import main

Expand All @@ -27,31 +25,23 @@ def close(self) -> None:


class CliTests(unittest.TestCase):
def test_main_renders_stdin_and_uses_selected_target(self) -> None:
def test_main_renders_stdin_to_target(self) -> None:
created: list[FakeLedController] = []

def factory(*, target_ip: str) -> FakeLedController:
controller = FakeLedController(target_ip=target_ip)
created.append(controller)
return controller

with tempfile.TemporaryDirectory() as directory:
config_path = Path(directory) / "matrix_display.toml"
config_path.write_text(
"[[display]]\n"
'target_display = "maksim"\n'
'controller_ip = "192.168.1.201"\n',
encoding="utf-8",
)
stderr = io.StringIO()

result = main(
["--config", str(config_path), "--target", "maksim"],
stdin=io.StringIO("Hello\n"),
controller_factory=factory,
sleep=lambda _: None,
stderr=stderr,
)
stderr = io.StringIO()

result = main(
["--target", "192.168.1.201"],
stdin=io.StringIO("Hello\n"),
controller_factory=factory,
sleep=lambda _: None,
stderr=stderr,
)

self.assertEqual(0, result)
self.assertEqual("", stderr.getvalue())
Expand All @@ -60,66 +50,26 @@ def factory(*, target_ip: str) -> FakeLedController:
self.assertTrue(created[0].closed)

def test_main_accepts_short_target_flag(self) -> None:
with tempfile.TemporaryDirectory() as directory:
config_path = Path(directory) / "matrix_display.toml"
config_path.write_text(
"[[display]]\n"
'target_display = "maksim"\n'
'controller_ip = "192.168.1.201"\n',
encoding="utf-8",
)

result = main(
["--config", str(config_path), "-t", "maksim"],
stdin=io.StringIO("Hello\n"),
controller_factory=lambda **_: FakeLedController("192.168.1.201"),
sleep=lambda _: None,
stderr=io.StringIO(),
)
result = main(
["-t", "192.168.1.201"],
stdin=io.StringIO("Hello\n"),
controller_factory=lambda **_: FakeLedController("192.168.1.201"),
sleep=lambda _: None,
stderr=io.StringIO(),
)

self.assertEqual(0, result)

def test_main_rejects_unknown_target(self) -> None:
stderr = io.StringIO()

with tempfile.TemporaryDirectory() as directory:
config_path = Path(directory) / "matrix_display.toml"
config_path.write_text(
"[[display]]\n"
'target_display = "maksim"\n'
'controller_ip = "192.168.1.201"\n',
encoding="utf-8",
)

result = main(
["--config", str(config_path), "--target", "office"],
stdin=io.StringIO("Hello\n"),
controller_factory=lambda **_: FakeLedController("192.168.1.201"),
sleep=lambda _: None,
stderr=stderr,
)

self.assertEqual(1, result)
self.assertIn("target display 'office' was not found", stderr.getvalue())

def test_main_rejects_empty_messages(self) -> None:
stderr = io.StringIO()
with tempfile.TemporaryDirectory() as directory:
config_path = Path(directory) / "matrix_display.toml"
config_path.write_text(
"[[display]]\n"
'target_display = "maksim"\n'
'controller_ip = "192.168.1.201"\n',
encoding="utf-8",
)

result = main(
["--config", str(config_path), "--target", "maksim"],
stdin=io.StringIO("\n"),
controller_factory=lambda **_: FakeLedController("192.168.1.201"),
sleep=lambda _: None,
stderr=stderr,
)

result = main(
["--target", "192.168.1.201"],
stdin=io.StringIO("\n"),
controller_factory=lambda **_: FakeLedController("192.168.1.201"),
sleep=lambda _: None,
stderr=stderr,
)

self.assertEqual(1, result)
self.assertIn("expected a message on stdin", stderr.getvalue())
Expand Down
Loading