Real-time LED sign control system built with Harper and Vue 3. Control multiple LED signs via MQTT with a responsive web interface featuring bidirectional real-time synchronization.
- Vue 3 web interface for LED sign control
- Real-time bidirectional sync between UI and hardware
- MQTT communication with Harper as broker
- State persistence in Harper database
- Server-Sent Events (SSE) for live updates
- Support for multiple LED signs
- Control message, brightness (0-15), and power state
%%{init: {'themeVariables': { 'edgeLabelBackground': 'transparent'}}}%%
flowchart TB
BROWSER[Browser<br/>Direct Control]
subgraph HARPER["Harper"]
direction BT
subgraph APPLICATION["Application"]
UI[Vue UI<br/>Message:String<br/>Brightness:Integer<br/>Power Controls:on or off]
end
subgraph MESSAGING["Messaging"]
MQTT["MQTT/MQTTS<br/>Ports: 1883,8883"]
9926["HTTP/REST/SSE/WS<br/>Port: 9926"]
end
subgraph CACHING["Caching<br/>(Not Used)"]
CACHE["Cache"]
end
subgraph DATABASE["Database"]
DB[(Topics Table<br/>- topic<br/>- value<br/>- updated_at)]
end
CACHING <-.-> | | APPLICATION
%% DATABASE <--> | | APPLICATION
DATABASE <--> | | MESSAGING
DATABASE <-.-> | | CACHING
end
SIGN1[LED Sign X]
SIGN2[LED Sign 2FE598]
UI --> |"HTTP PUT :9926<br/>/Topics/{topic}"| 9926
9926 --> |"SSE :9926<br/>/subscribe?table=Topics"| UI
BROWSER <-.-> |"HTTP :80 (Direct Control)"| SIGN2
BROWSER <-.-> |"HTTP :9926"|HARPER
HARPER <-->|"MQTT :1883<br/>led-sign/#"| SIGN1
HARPER <-->|"MQTT :1883<br/>led-sign/#"| SIGN2
UI@{ shape : rounded }
SIGN1@{ shape : rounded }
SIGN2@{ shape : rounded }
9926@{ shape : rounded }
MQTT@{ shape : rounded }
BROWSER@{ shape : rounded }
linkStyle default stroke-width:2px,fill:none,stroke:#000,color:#fff
CACHE@{ shape: rounded }
style HARPER fill:#9B61FC,stroke:#000000,color:#ffffff
style APPLICATION fill:#c3a1ff,stroke:#000000,color:#ffffff
style CACHING fill:#c3a1ff,stroke:#000000,color:#ffffff
style MESSAGING fill:#c3a1ff,stroke:#000000,color:#ffffff
style DATABASE fill:#c3a1ff,stroke:#000000,color:#ffffff
style DB fill:#48bb78,stroke:#2f855a,color:#fff
style SIGN1 fill:#5d85fc,stroke:#000000,color:#fff
style SIGN2 fill:#5d85fc,stroke:#000000,color:#fff
style BROWSER fill:#fcb45d,stroke:#64748b,color:#1e293b,opacity:0.7
style UI fill:#7221ff,stroke:#fff,color:#fff
style CACHE fill:#7221ff,stroke:#fff,color:#fff
style DB fill:#7221ff,stroke:#fff,color:#fff
style 9926 fill:#7221ff,stroke:#fff,color:#fff
style MQTT fill:#7221ff,stroke:#fff,color:#fff
Write Path (User → LED Sign):
- User changes value in Vue UI (optimistic update)
- Vue sends REST PUT to Harper
/Topics/{topic-path} - Harper persists to Topics table
- Harper auto-publishes to MQTT topic
- LED sign receives MQTT message and updates
Read Path (LED Sign → User):
- LED sign publishes state to Harper MQTT broker
- Harper updates Topics table automatically
- Harper sends SSE event to connected clients
- Vue receives update and syncs UI state
led-sign/<sign-id>/message # Display text
led-sign/<sign-id>/brightness # 0-15 integer
led-sign/<sign-id>/power # "on" or "off"
Example: led-sign/2FE598/message with value "Hello World"
- Harper:
npm install -g harperdb - Node.js 16+ for Vue development
-
Clone this repository
-
Install dependencies:
npm install
-
Configure environment (
.env):VITE_HARPER_URL=http://localhost:9926 VITE_SIGN_ID=2FE598
-
Start Harper:
harperdb run . -
In development, run Vue dev server:
npm run dev
-
For production, build Vue app (outputs to
dist/):npm run build
Harper serves the built app automatically from
dist/
Configure your LED sign (ESP32 or similar) to connect to Harper's MQTT broker:
- Broker (MQTT):
<your-harper-host>:1883(TCP) or:8883(TLS) - Subscribe to:
led-sign/<your-sign-id>/# - Publish to:
led-sign/<your-sign-id>/{message|brightness|power}
- HTTP/REST:
:9926- REST API endpoints - SSE/WebSocket:
:9926- Real-time subscriptions - MQTT (TCP):
:1883- Standard MQTT - MQTTS (TLS):
:8883- Secure MQTT over TLS
.
├── config.yaml # Harper configuration (REST & static files)
├── schema.graphql # Database schema (Topics table)
├── resources.js # Custom resource logic (optional)
├── src/
│ ├── App.vue # Main Vue component
│ ├── main.js # Vue entry point
│ └── services/
│ └── harperApi.js # Harper REST/SSE client
├── docs/
│ └── plans/ # Design documents
└── dist/ # Built Vue app (served by Harper)
Harper configuration specifying REST API, static file serving, and schema location.
Database schema defining the Topics table for MQTT state persistence:
type Topics @table @export(name: "") {
topic: String @primaryKey
value: String
updated_at: DateTime
}Optional JavaScript resource classes for custom endpoint logic.
npm testUse mqtt-test.js to send test messages:
node mqtt-test.jsSee Design Document for detailed architecture, implementation details, and testing strategy.
Apache 2.0