IoT Directory Structure
The IoT module contains several scripts for bidirectional communication between Raspberry Pi hardware and SignPlayer. Each file serves a specific purpose in the IoT ecosystem.
Complete documentation for IoT integration scripts
Web portal, sensors, relays, and audio playback
[ Node.js | GPIO | SignService API ]
The IoT module contains several scripts for bidirectional communication between Raspberry Pi hardware and SignPlayer. Each file serves a specific purpose in the IoT ecosystem.
iot/iotWebPortal.js
A web-based developer portal for testing and debugging IoT events. Provides a visual interface to send events to SignPlayer, register event listeners, view received events in real-time, and configure SignService connection.
# Start the web portal node iotWebPortal.js # Opens browser automatically to http://localhost:5000
+-----------------------------------------------------------------------------+ | IoT Web Portal | | Port 5000 | +-----------------------------------------------------------------------------+ | | | +---------------------------+ +---------------------------+ | | | HTTP Server | | SSE Event Stream | | | | - Serves HTML UI | | - Real-time updates | | | | - REST endpoints | | - Client notifications | | | +---------------------------+ +---------------------------+ | | | | +---------------------------+ +---------------------------+ | | | SignService Client | | Callback Server | | | | - Send events | | - Receive callbacks | | | | - Register listeners | | - Forward to UI | | | +---------------------------+ +---------------------------+ | | | +-----------------------------------------------------------------------------+
| Feature | Description |
|---|---|
| Send to Player | Send JSON events directly to SignPlayer |
| Event Listeners | Register callbacks for specific events |
| Real-time Display | See received events instantly via SSE |
| IP Detection | Auto-detects local IP for callback URL |
| SignService Config | Configure which SignService to connect to |
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Serves HTML UI |
/events |
GET | SSE stream for real-time updates |
/callback |
POST | Receives events from SignService |
/register |
POST | Register event listener |
/unregister |
POST | Unregister event listener |
/send |
POST | Send event to SignPlayer |
/registeredEvents |
GET | List registered events |
/setSignServiceHost |
POST | Configure SignService IP |
/getCallbackHost |
GET | Get this device's IP |
| Parameter | Default | Description |
|---|---|---|
PORT |
5000 | Web portal port |
SIGNSERVICE_PORT |
8094 | SignService HTTPS port |
SIGNSERVICE_HOST |
localhost | Can be changed via UI |
function getLocalIP() { const interfaces = os.networkInterfaces(); // Skip virtual adapters (VMware, VirtualBox, Docker, etc.) const skipNames = ['vmware', 'virtualbox', 'vbox', 'docker', 'vethernet', 'hyper-v']; const skipRanges = ['192.168.56.', '192.168.45.', '172.17.', '172.18.', '10.0.2.']; // Prefer common LAN ranges const preferredRanges = ['192.168.68.', '192.168.1.', '192.168.0.', '10.0.0.', '10.0.1.']; // ... returns best IP address }
function registerEventWithSignService(eventName) { const callbackUrl = encodeURIComponent(`http://${CALLBACK_HOST}:${PORT}/callback`); const path = `/player/registerEvent?eventName=${eventName}&callbackUrl=${callbackUrl}`; // POST to SignService HTTPS endpoint }
function sendEventToPlayer(eventName, jsonData) { const path = `/player/sendEvent?eventName=${eventName}&store=1`; // POST JSON data to SignService }
function broadcastToClients(data) { const message = `data: ${JSON.stringify(data)}\n\n`; sseClients.forEach(client => { client.write(message); }); }
iot/iotSendTemperture.js
Reads temperature from a DHT11 sensor and sends it to SignPlayer every 4 seconds. Includes a demo mode for testing without hardware.
# Demo mode (simulated temperature) node iotSendTemperture.js # Live mode (real DHT11 sensor) # Edit file: change DEMO = false node iotSendTemperture.js
+-----------------------------------------------------------------------------+
| Temperature Sender Flow |
+-----------------------------------------------------------------------------+
+----------+ +-------------+ +-------------+ +-------------+
| DHT11 | | Node.js | | SignService | | SignPlayer |
| Sensor | ---> | Script | ---> | (C#) | ---> | Display |
+----------+ +-------------+ +-------------+ +-------------+
| | | |
| GPIO 5 | | |
| Read | | |
| Every 4s | | |
| | POST JSON: | |
| | {"name": "25.3"} | |
| | | |
| Parameter | Default | Description |
|---|---|---|
DEMO |
true | true = simulated, false = real sensor |
SIGNSERVICE_HOST |
localhost | Windows PC IP running SignService |
SIGNSERVICE_PORT |
8094 | SignService HTTPS port |
EVENT_NAME |
myCustomEvent | Must match SignStudio config |
POLL_INTERVAL |
4 | Seconds between readings |
SENSOR_PIN |
5 | GPIO pin for DHT11 data |
function sendTemperature(temp_c, temp_f, humidity) { const data = JSON.stringify({ name: varied_c + ' degrees' }); // Direct HTTPS POST to SignService const curlCmd = `curl '${IOT_SERVER}' \ -X POST \ -H 'Content-Type: application/json' \ --data-raw '${data}' \ --insecure \ --silent`; exec(curlCmd, (error, stdout, stderr) => { // Handle response }); }
function addVariance(value) { const variance = (Math.random() - 0.5) * 0.6; // -0.3 to +0.3 return Math.round((value + variance) * 10) / 10; }
To display the temperature in SignPlayer, create a Label component with data binding:
{
"Label": [{
"Text": ["Temperature"],
"DataBinding": {
"eventName": "myCustomEvent",
"field": "name"
}
}]
}
iot/iotReceiveAlertRelay.js
Listens for events from SignPlayer and controls a relay on GPIO 4. When a user touches a button in SignPlayer, this script receives the event and turns the relay ON or OFF.
# Default event name: clickAlarm node iotReceiveAlertRelay.js # Custom event name node iotReceiveAlertRelay.js myEventName
+-----------------------------------------------------------------------------+
| Relay Control Flow |
+-----------------------------------------------------------------------------+
+-------------+ +-------------+ +-------------+ +----------+
| SignPlayer | | SignService | | Node.js | | Relay |
| (Touch) | ---> | (C#) | ---> | Script | ---> | GPIO 4 |
+-------------+ +-------------+ +-------------+ +----------+
| | | |
| User taps | | |
| "Alarm ON" | | |
| button | | |
| | HTTP Callback: | |
| | {"data": { | |
| | "clickAlarm": | |
| | "on"}} | |
| | | GPIO Write: |
| | | Pin 4 = HIGH |
| | | |
| Parameter | Default | Description |
|---|---|---|
RELAY_PIN |
4 | GPIO pin for relay (Pin 7 on header) |
PORT |
5001 | Callback server port |
SIGNSERVICE_HOST |
localhost | SignService IP address |
SIGNSERVICE_PORT |
8094 | SignService HTTPS port |
DEFAULT_EVENT_NAME |
clickAlarm | Event to listen for |
REGISTER_INTERVAL |
5 | Re-register every N seconds |
function initGpio() { const cmd = `python3 -c "import lgpio; h=lgpio.gpiochip_open(0); lgpio.gpio_claim_output(h, ${RELAY_PIN}); lgpio.gpio_write(h, ${RELAY_PIN}, 0); lgpio.gpiochip_close(h)"`; exec(cmd, (err) => { if (!err) gpioInitialized = true; }); }
function setRelay(on) { const value = on ? 1 : 0; const cmd = `python3 -c "import lgpio; h=lgpio.gpiochip_open(0); lgpio.gpio_claim_output(h, ${RELAY_PIN}); lgpio.gpio_write(h, ${RELAY_PIN}, ${value}); lgpio.gpiochip_close(h)"`; exec(cmd, (err) => { console.log(`>>> RELAY ${on ? 'ON' : 'OFF'}`); }); }
// In HTTP server callback handler: if (json.data && json.data.clickAlarm) { const alarmState = json.data.clickAlarm.toLowerCase(); if (alarmState.includes('on')) { setRelay(true); } else if (alarmState.includes('off')) { setRelay(false); } }
+-------------+ +---------------------+ | Relay | | Raspberry Pi | | Module | | | |-------------| |---------------------| | VCC (red) |---->| Pin 2 (5V) | | IN (yellow) |---->| Pin 7 (GPIO 4) | | GND (black) |---->| Pin 6 (GND) | +-------------+ +---------------------+
Create a Button component with EventCommands:
{
"$": {
"player": "7000",
"label": "Alarm Button"
},
"Data": [{
"Button": [{
"$": {
"label": "Alarm ON",
"fieldName": "alarmButton"
}
}],
"EventCommands": [{
"EventCommand": [{
"$": {
"from": "click",
"command": "sendEvent"
},
"Params": {
"eventName": "clickAlarm",
"data": {
"clickAlarm": "on"
}
}
}]
}]
}]
}
iot/iotReceiveAlertAudio.js
Similar to iotReceiveAlertRelay.js, but plays audio instead of controlling a relay. Uses the speaker.py Python script to play alarm sounds.
# Default event name: clickAlarm node iotReceiveAlertAudio.js # Custom event name node iotReceiveAlertAudio.js myEventName
+-----------------------------------------------------------------------------+
| Audio Control Flow |
+-----------------------------------------------------------------------------+
+-------------+ +-------------+ +-------------+ +----------+
| SignPlayer | | SignService | | Node.js | | Speaker |
| (Touch) | ---> | (C#) | ---> | Script | ---> | (Audio) |
+-------------+ +-------------+ +-------------+ +----------+
| | | |
| User taps | | |
| "Alarm ON" | | |
| button | | |
| | HTTP Callback: | |
| | {"data": { | |
| | "clickAlarm": | |
| | "on"}} | |
| | | Play sound: |
| | | speaker.py |
| | | gas_alarm |
| | | |
| Parameter | Default | Description |
|---|---|---|
SPEAKER_SCRIPT |
/root/_node-dev/pi/lib/speaker.py | Path to audio playback script |
ALARM_TYPE |
gas_alarm | Type of alarm sound to play |
PORT |
5002 | Different port from relay version |
DEBOUNCE_MS |
500 | Ignore rapid duplicate calls |
function playAlarm() { const now = Date.now(); if (now - lastPlayTime < DEBOUNCE_MS) return; // Debounce if (isPlaying) return; // Already playing isPlaying = true; const cmd = `python3 ${SPEAKER_SCRIPT} ${ALARM_TYPE}`; exec(cmd, (err, stdout, stderr) => { isPlaying = false; }); }
function stopAlarm() { exec('pkill -f "speaker.py" 2>/dev/null', () => { isPlaying = false; }); }
| Feature | iotReceiveAlertRelay.js | iotReceiveAlertAudio.js |
|---|---|---|
| Port | 5001 | 5002 |
| Output | GPIO Relay | Audio Speaker |
| Control | setRelay(true/false) | playAlarm()/stopAlarm() |
| Debounce | No | Yes (500ms) |
| Hardware | Relay Module | Speaker/Audio Hat |
iot/iotSendCurl.sh
Example curl command for testing event sending from the command line. Useful for debugging and understanding the API.
curl 'http://localhost:5000/send?eventName=myCustomEvent' \ -H 'Accept: */*' \ -H 'Content-Type: application/json' \ --data-rawlive examples, see it in action
Checkout live examples of Digital Signage presentations. The SignPlayer can run everywhere, on Android, Windows, Mac, iPad and even inside your web browser
View Moreproduct pricing
Find out why people call us “the world’s most popular digital signage platform”
View More