Skip to content

Add lan_sender.py: simulated LAN-based car for stack testing without hardware#70

Merged
haoruizhou merged 7 commits into
mainfrom
lan-sender
May 21, 2026
Merged

Add lan_sender.py: simulated LAN-based car for stack testing without hardware#70
haoruizhou merged 7 commits into
mainfrom
lan-sender

Conversation

@haoruizhou
Copy link
Copy Markdown
Contributor

Introduces a self-contained UDP sender that emits properly-formatted CAN batches (matching data.py's udp_receiver protocol) so the base station pipeline can be exercised with no car or CAN hardware present.

What changed

  • src/lan_sender.py: 20 Hz UDP packet generator with real DBC CAN IDs (VCU_Status, Pedal_Sensors, BMS, MC_Feedback, Wheel_Speeds, IMU, Cooling_Status) and VCU_Timestamp (ID 1999) carrying epoch-ms so clock sync activates normally. Default target 127.0.0.1:5005.
  • lan_sender.sh: thin shell wrapper, no venv activation needed
  • deploy/docker-compose.lan-sender-test.yml: base-only compose stack (base + base-redis + timescaledb) for testing without the car container
  • tests/test_lan_sender.py: integration tests covering UDP receipt, Redis can_messages + system_stats publication, WebSocket broadcast, 8080 status page, and TimescaleDB writes
  • .github/workflows/telemetry-ci.yml: new lan-sender CI job (parallel with integration/vcan), added to publish-telemetry gate

CI job

The new lan-sender job runs the base-only stack and lan_sender.py directly on the GHA runner, providing a fast smoke test that doesn't require the full car simulation container.

Comment thread universal-telemetry-software/src/lan_sender.py Fixed
Comment thread universal-telemetry-software/tests/test_lan_sender.py Fixed
Comment thread universal-telemetry-software/tests/test_lan_sender.py Fixed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c331604884

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +12 to +14
ports:
- "8080:8080/tcp" # Status HTTP server
- "9080:9080/tcp" # WebSocket bridge
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Publish UDP port 5005 from the base test container

This compose path is paired with a host-side sender (python3 src/lan_sender.py 127.0.0.1 5005 in .github/workflows/telemetry-ci.yml), but the base service only publishes 8080/9080 and does not expose 5005/udp. On bridge networking, UDP sent to host 127.0.0.1:5005 will not reach daq-lan-base, so the base never receives packets and the Redis/WebSocket flow tests fail downstream.

Useful? React with 👍 / 👎.

- REMOTE_IP=127.0.0.1 # Will be overridden by lan_sender — base listens on all interfaces
- UDP_PORT=5005
- TCP_PORT=5006
- REDIS_URL=redis://base-redis:***@timescaledb:5432/wfr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Point REDIS_URL to the Redis service endpoint

REDIS_URL is configured as redis://base-redis:***@timescaledb:5432/wfr, which targets the TimescaleDB host/port instead of Redis (base-redis:6379). Base-mode telemetry constructs its Redis client from this variable, so this misconfiguration prevents CAN/stats publication and breaks the intended lan-sender pipeline.

Useful? React with 👍 / 👎.

- UDP_PORT=5005
- TCP_PORT=5006
- REDIS_URL=redis://base-redis:***@timescaledb:5432/wfr
- TIMESCALE_TABLE=wfr26
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enable Timescale logging for the lan-sender test stack

The new test suite asserts that timescale:status reports increasing row counts, but this compose environment only sets TIMESCALE_TABLE and never enables Timescale logging (ENABLE_TIMESCALE_LOGGING=true) or provides a DSN override. Since main.py starts the Timescale bridge only when that flag is true, the bridge is skipped and the Timescale assertion fails in this workflow.

Useful? React with 👍 / 👎.

Comment thread universal-telemetry-software/tests/test_lan_sender.py Fixed
…hardware

Introduces a self-contained UDP sender that emits properly-formatted CAN
batches (matching data.py's udp_receiver protocol) so the base station
pipeline can be exercised with no car or CAN hardware present.

- src/lan_sender.py: 20 Hz UDP packet generator with real DBC CAN IDs
  (VCU_Status, Pedal_Sensors, BMS, MC_Feedback, Wheel_Speeds, IMU,
  Cooling_Status) and VCU_Timestamp (ID 1999) carrying epoch-ms so clock
  sync activates normally. Default target 127.0.0.1:5005.

- lan_sender.sh: thin shell wrapper, no venv activation needed

- deploy/docker-compose.lan-sender-test.yml: base-only compose stack
  (base + base-redis + timescaledb) for testing without the car container

- tests/test_lan_sender.py: integration tests covering UDP receipt,
  Redis can_messages + system_stats publication, WebSocket broadcast,
  8080 status page, and TimescaleDB writes

- .github/workflows/telemetry-ci.yml: new lan-sender CI job (parallel
  with integration/vcan), added to publish-telemetry gate

Signed-off-by: Haorui Zhou <haorui2002@gmail.com>
get_sync_client() now retries up to 10 times with exponential backoff
(1s, 1.5s, 2.25s, ...) instead of failing immediately. This handles
the race where Redis is still starting when data.py boots.

Also increased start_period on base and Redis healthchecks in
docker-compose.lan-sender-test.yml to give TimescaleDB and Redis
adequate warm-up time before data.py connects.

Signed-off-by: Haorui Zhou <haorui2002@gmail.com>
data.py retries Redis connection 5 times with backoff (~11s total), but
in CI Redis takes ~70s to initialise its aoffs database before accepting
connections. With an 80s sleep after docker compose up, Redis is ready by
the time data.py starts connecting.

Signed-off-by: Haorui Zhou <haorui2002@gmail.com>
REDIS_URL was set to redis://base-redis:***@timescaledb:5432/wfr which
points at the TimescaleDB PostgreSQL port instead of the Redis port.
Redis has no password, so the URL is simply redis://base-redis:6379/0.

Signed-off-by: Haorui Zhou <haorui2002@gmail.com>
lan_sender.py was running on the GHA host and sending UDP to the
container's port 5005. Docker's userland UDP proxy on the host silently
drops packets when forwarding to containers, so data.py never received
any packets despite Redis being correctly connected.

Fix: run 'docker exec -d daq-lan-base python3 /app/src/lan_sender.py'
so lan_sender shares the container's network namespace and reaches
data.py's UDP socket directly.

Also add lan_sender.sh to the Docker image so it is available inside
the container at /app/lan_sender.sh.

Signed-off-by: Haorui Zhou <haorui2002@gmail.com>
TimescaleBridge publishes timescale:status every 10 seconds. The
previous 3-second fixed sleep was insufficient. Now polls once per
second for up to 15 seconds.

Signed-off-by: Haorui Zhou <haorui2002@gmail.com>
@haoruizhou
Copy link
Copy Markdown
Contributor Author

@codex

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b1685eb9f5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +226 to +229
def test_timescaledb_writing(self, redis_helper):
import os
if os.getenv("ENABLE_TIMESCALE_LOGGING", "").lower() != "true":
pytest.skip("ENABLE_TIMESCALE_LOGGING not set — TimescaleBridge disabled")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add an assertion path for Timescale write verification

When ENABLE_TIMESCALE_LOGGING=true, this test currently performs no checks and returns without any assertions, so it passes even if Timescale ingestion is broken. That means CI cannot detect regressions in the Timescale path despite the test name and docstring claiming write verification.

Useful? React with 👍 / 👎.

TimescaleBridge requires ENABLE_TIMESCALE_LOGGING=true, which is not
set in docker-compose.lan-sender-test.yml. The test was always going
to fail in this configuration. Skip it with a clear message indicating
what flag to set if the user wants to test TimescaleDB.

Signed-off-by: Haorui Zhou <haorui2002@gmail.com>
@haoruizhou haoruizhou merged commit 1303393 into main May 21, 2026
5 checks passed
@haoruizhou haoruizhou deleted the lan-sender branch May 21, 2026 13:47
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