UnitAPI (Unit Hardware API) is a comprehensive Python framework for managing and interacting with network-connected hardware devices across different platforms and protocols. It provides a unified, flexible, and secure approach to device communication and control.
- Automatic device discovery
- Dynamic device registration
- Multi-protocol support
- Flexible device abstraction
- WebSocket
- MQTT
- Custom protocol extensions
- Token-based authentication
- Encryption
- Access control
- Audit logging
- Cameras
- Microphones
- Speakers
- GPIO Controllers
- Custom device implementations
graph TD
A[Device Layer] --> B[Protocol Layer]
B --> C[Core Framework]
subgraph "Device Layer"
A1[Device Types]
end
subgraph "Protocol Layer"
B1[Protocols]
end
subgraph "Core Framework"
C1[Server]
C2[Client]
C3[Security]
end
graph TD
Client[Client API] --> |Requests| Server[Server API]
Server --> |Manages| Devices[Device Registry]
Server --> |Uses| Security[Security Module]
Server --> |Communicates via| Protocols[Protocol Handlers]
Protocols --> |Connect to| Devices
subgraph "Device Types"
D1[Camera]
D2[Microphone]
D3[Speaker]
D4[GPIO]
D5[Input Devices]
end
Devices --> D1
Devices --> D2
Devices --> D3
Devices --> D4
Devices --> D5
classDiagram
BaseDevice <|-- Camera
BaseDevice <|-- Microphone
BaseDevice <|-- Speaker
BaseDevice <|-- GPIO
BaseDevice <|-- InputDevice
InputDevice <|-- Keyboard
InputDevice <|-- Mouse
InputDevice <|-- Touchscreen
InputDevice <|-- Gamepad
class BaseDevice {
+device_id: str
+device_type: str
+metadata: dict
+connect()
+disconnect()
+is_connected(): bool
}
class Camera {
+capture_frame()
+start_stream()
+stop_stream()
}
class Microphone {
+record_audio()
+start_recording()
+stop_recording()
}
class Speaker {
+play_audio()
+set_volume()
+get_volume()
}
sequenceDiagram
participant Client
participant Server
participant Device
Client->>Server: Connect()
Server-->>Client: Connection Established
Client->>Server: List Devices()
Server-->>Client: Available Devices
Client->>Server: Connect to Device(device_id)
Server->>Device: Establish Connection
Device-->>Server: Connection Status
Server-->>Client: Device Connected
Client->>Server: Send Command(device_id, command, params)
Server->>Device: Execute Command
Device-->>Server: Command Result
Server-->>Client: Command Response
Client->>Server: Disconnect from Device(device_id)
Server->>Device: Close Connection
Device-->>Server: Disconnected
Server-->>Client: Device Disconnected
Client->>Server: Disconnect()
Server-->>Client: Connection Closed
flowchart TD
A[Start Discovery] --> B{Local Network Scan}
B --> C[Find Devices]
C --> D{For Each Device}
D --> E[Query Device Info]
E --> F{Supported Protocol?}
F -->|Yes| G[Register Device]
F -->|No| H[Skip Device]
G --> I[Next Device]
H --> I
I --> J{More Devices?}
J -->|Yes| D
J -->|No| K[Discovery Complete]
stateDiagram-v2
[*] --> Disconnected
Disconnected --> Connecting: connect()
Connecting --> Connected: connection_established
Connecting --> Error: connection_failed
Connected --> Active: device_ready
Active --> Idle: no_activity
Idle --> Active: new_command
Active --> Error: command_failed
Error --> Reconnecting: auto_reconnect
Reconnecting --> Connected: reconnection_successful
Reconnecting --> Disconnected: reconnection_failed
Connected --> Disconnecting: disconnect()
Active --> Disconnecting: disconnect()
Idle --> Disconnecting: disconnect()
Disconnecting --> Disconnected: disconnection_complete
Disconnected --> [*]
graph TD
subgraph "Cloud Environment"
CloudServer[Central Management Server]
Database[(Device Registry DB)]
CloudServer --- Database
end
subgraph "Local Network A"
GatewayA[Local Gateway]
DeviceA1[Camera]
DeviceA2[Microphone]
DeviceA3[Speaker]
GatewayA --- DeviceA1
GatewayA --- DeviceA2
GatewayA --- DeviceA3
end
subgraph "Local Network B"
GatewayB[Local Gateway]
DeviceB1[GPIO Controller]
DeviceB2[Input Devices]
GatewayB --- DeviceB1
GatewayB --- DeviceB2
end
subgraph "Remote Devices"
RemoteDevice1[Remote Camera]
RemoteDevice2[Remote Speaker]
end
CloudServer --- GatewayA
CloudServer --- GatewayB
CloudServer --- RemoteDevice1
CloudServer --- RemoteDevice2
Client1[Client Application] --- CloudServer
Client2[Client Application] --- GatewayA
Client3[Client Application] --- GatewayB
graph TD
subgraph "Internet"
Cloud[Cloud Services]
end
subgraph "Home Network"
Router[Home Router]
Server[UnitAPI Server]
Dev1[Camera]
Dev2[Microphone]
Dev3[Speaker]
Router --- Server
Server --- Dev1
Server --- Dev2
Server --- Dev3
end
subgraph "Remote Location"
RemoteRouter[Remote Router]
RemoteDev1[Remote Camera]
RemoteDev2[Remote Microphone]
RemoteRouter --- RemoteDev1
RemoteRouter --- RemoteDev2
end
Cloud --- Router
Cloud --- RemoteRouter
Client[Client Application] --- Cloud
LocalClient[Local Client] --- Server
gantt
title UnitAPI Implementation Timeline
dateFormat YYYY-MM-DD
section Planning
Requirements Analysis :a1, 2024-01-01, 14d
Architecture Design :a2, after a1, 21d
section Development
Core Framework :d1, after a2, 30d
Protocol Implementation :d2, after d1, 21d
Device Types :d3, after d1, 28d
Security Features :d4, after d2, 14d
section Testing
Unit Testing :t1, after d3, 14d
Integration Testing :t2, after t1, 14d
Performance Testing :t3, after t2, 7d
section Deployment
Documentation :p1, after d4, 14d
Example Creation :p2, after p1, 7d
Release :milestone, after t3, 0d
pie title Device Types in Typical Deployment
"Cameras" : 25
"Microphones" : 20
"Speakers" : 20
"Input Devices" : 15
"GPIO Controllers" : 10
"Custom Devices" : 10
journey
title UnitAPI User Experience
section Discovery
Find UnitAPI: 5: User
Read Documentation: 3: User
Evaluate Features: 4: User
section Installation
Install Package: 5: User, Developer
Configure Environment: 3: Developer
Test Installation: 4: Developer
section Development
Create Server: 5: Developer
Register Devices: 4: Developer
Implement Client: 3: Developer
section Deployment
Test in Production: 2: Developer, Admin
Monitor Performance: 3: Admin
Scale System: 4: Admin
section Maintenance
Update Framework: 3: Developer, Admin
Add New Devices: 5: Developer
Troubleshoot Issues: 2: Developer, Admin
pip install unitapi
# Install with specific protocol support
pip install unitapi[mqtt]
pip install unitapi[websocket]
from unitapi.core.server import UnitAPIServer
# Create a server instance
server = UnitAPIServer(host='0.0.0.0', port=7890)
# Register a device
server.register_device(
device_id='temp_sensor_01',
device_type='sensor',
metadata={
'location': 'living_room',
'capabilities': ['temperature', 'humidity']
}
)
# Start the server
server.start()
from unitapi.core.client import UnitAPIClient
# Create a client
client = UnitAPIClient(server_host='localhost', server_port=7890)
# List available devices
devices = client.list_devices()
print("Available Devices:", devices)
- Represent physical or virtual network-connected devices
- Provide a consistent interface for interaction
- Support custom device type creation
- Abstraction layer for different communication methods
- Easy integration of new protocols
- Seamless device communication
- Comprehensive authentication mechanisms
- Fine-grained access control
- Encryption of device communications
- Smart Home Automation
- Industrial IoT
- Remote Monitoring
- Network Device Management
- Distributed Sensor Networks
- Remote Audio Control
We welcome contributions! Please read our Contribution Guidelines for details on how to get started.
- GitHub Issues: UnitAPI Issues
- Email: support@unitapi.com
UnitAPI is open-source software licensed under the MIT License.
Current Version: 0.1.5
- Python 3.8+
- Supported Platforms:
- Windows 10/11
- macOS 10.15+
- Linux (Ubuntu 20.04+, Debian 10+)
- Raspberry Pi (Raspbian/Raspberry Pi OS)
- Low-latency device communication
- Minimal overhead
- Scalable architecture
- Async-first design
- Enhanced machine learning integration
- More device type support
- Advanced discovery mechanisms
- Cloud service integrations
- Improved remote device management
UnitAPI is an evolving project. While we strive for stability, the API may change in future versions.
Thanks to all contributors and the open-source community for making this project possible.
UnitAPI supports various device types, each with its own capabilities and interfaces. This document provides detailed information about the built-in device types and how to create custom device types.
UnitAPI's device abstraction layer provides a consistent interface for interacting with different types of hardware and virtual devices. Each device type inherits from the BaseDevice
class and implements specific functionality relevant to that device category.
UnitAPI device types are organized into the following categories:
- Sensor Devices: Devices that capture data from the environment (cameras, microphones, etc.)
- Output Devices: Devices that produce output (speakers, displays, etc.)
- Input Devices: Devices that accept user input (mouse, keyboard, touchscreen, gamepad, etc.)
- GPIO Devices: Devices that interact with general-purpose input/output pins
Camera devices provide interfaces for capturing images and video streams.
- Image capture
- Video streaming
- Camera configuration (resolution, FPS)
- Connection management
from unitapi.devices.camera import CameraDevice
import asyncio
async def main():
# Create a camera device
camera = CameraDevice(
device_id='camera_01',
name='Main Camera',
metadata={
'resolution': '1080p',
'fps': 30,
'location': 'front_door'
}
)
# Connect to the camera
await camera.connect()
# Capture an image
image_data = await camera.capture_image()
print(f"Image captured: {image_data}")
# Start a video stream
stream_info = await camera.start_video_stream(duration=10)
print(f"Stream started: {stream_info}")
# Disconnect when done
await camera.disconnect()
asyncio.run(main())
Microphone devices provide interfaces for recording audio.
- Audio recording
- Sample rate and channel configuration
- Connection management
from unitapi.devices.microphone import MicrophoneDevice
import asyncio
async def main():
# Create a microphone device
mic = MicrophoneDevice(
device_id='mic_01',
name='Desktop Microphone',
metadata={
'sample_rate': 44100,
'channels': 2,
'location': 'office'
}
)
# Connect to the microphone
await mic.connect()
# Record audio
audio_data = await mic.record_audio(duration=5, sample_rate=44100)
print(f"Audio recorded: {audio_data}")
# Disconnect when done
await mic.disconnect()
asyncio.run(main())
GPIO (General Purpose Input/Output) devices provide interfaces for controlling digital pins, typically on devices like Raspberry Pi.
- Pin mode configuration (input/output)
- Digital read/write operations
- PWM (Pulse Width Modulation) control
- Connection management
from unitapi.devices.gpio import GPIODevice
import asyncio
async def main():
# Create GPIO device
gpio = GPIODevice(
device_id='rpi_gpio_01',
name='Raspberry Pi GPIO',
metadata={'total_pins': 40}
)
# Connect to the GPIO device
await gpio.connect()
# Set pin mode and control
await gpio.set_pin_mode(18, 'output')
await gpio.digital_write(18, True)
# Read from a pin
await gpio.set_pin_mode(17, 'input')
pin_value = await gpio.digital_read(17)
print(f"Pin 17 value: {pin_value}")
# PWM control
await gpio.set_pin_mode(12, 'output')
await gpio.pwm_write(12, 0.5) # 50% duty cycle
# Disconnect when done
await gpio.disconnect()
asyncio.run(main())
Speaker devices provide interfaces for playing audio.
- Audio playback
- Volume control
- Audio format configuration
- Connection management
from unitapi.devices.remote_speaker_device import RemoteSpeakerDevice
import asyncio
async def main():
# Create a speaker device
speaker = RemoteSpeakerDevice(
device_id='speaker_01',
name='Living Room Speaker',
metadata={
'sample_rate': 44100,
'channels': 2,
'location': 'living_room'
}
)
# Connect to the speaker
await speaker.connect()
# Play audio
await speaker.play_audio('path/to/audio.wav')
# Play a test tone
await speaker.play_test_tone(frequency=440, duration=2.0)
# Disconnect when done
await speaker.disconnect()
asyncio.run(main())
Mouse devices provide interfaces for controlling cursor movement and button actions.
- Cursor movement (absolute and relative)
- Button actions (click, double-click, press, release)
- Scrolling
- Drag operations
- Connection management
from unitapi.devices import MouseDevice
import asyncio
async def main():
# Create a mouse device
mouse = MouseDevice(
device_id='mouse_01',
name='Virtual Mouse',
metadata={'dpi': 1200}
)
# Connect to the mouse
await mouse.connect()
# Move the mouse to an absolute position
await mouse.move_to(500, 300)
# Perform a left click
await mouse.click()
# Perform a right click
await mouse.click(button="right")
# Perform a drag operation
await mouse.drag(700, 400)
# Scroll the mouse wheel
await mouse.scroll(5) # Scroll up
# Disconnect when done
await mouse.disconnect()
asyncio.run(main())
Keyboard devices provide interfaces for simulating keyboard input.
- Key press and release
- Text typing
- Hotkey combinations
- Modifier key support
- Connection management
from unitapi.devices import KeyboardDevice
import asyncio
async def main():
# Create a keyboard device
keyboard = KeyboardDevice(
device_id='keyboard_01',
name='Virtual Keyboard',
metadata={'layout': 'us'}
)
# Connect to the keyboard
await keyboard.connect()
# Type some text
await keyboard.type_text("Hello, UnitAPI!")
# Press individual keys
await keyboard.press_key("a")
# Press a hotkey combination (Ctrl+C)
await keyboard.press_hotkey("ctrl", "c")
# Disconnect when done
await keyboard.disconnect()
asyncio.run(main())
Touchscreen devices provide interfaces for simulating touch input.
- Single and multi-touch support
- Tap and double-tap gestures
- Swipe gestures
- Pinch gestures (zoom in/out)
- Rotation gestures
- Connection management
from unitapi.devices import TouchscreenDevice
import asyncio
async def main():
# Create a touchscreen device
touchscreen = TouchscreenDevice(
device_id='touchscreen_01',
name='Virtual Touchscreen',
metadata={
'width': 1920,
'height': 1080,
'multi_touch': True
}
)
# Connect to the touchscreen
await touchscreen.connect()
# Perform a tap
await touchscreen.tap(500, 300)
# Perform a swipe
await touchscreen.swipe(200, 500, 800, 500, duration=0.5)
# Perform a pinch (zoom out)
await touchscreen.pinch(
center_x=960,
center_y=540,
start_distance=200,
end_distance=100,
duration=0.5
)
# Disconnect when done
await touchscreen.disconnect()
asyncio.run(main())
Gamepad devices provide interfaces for simulating game controller input.
- Button press and release
- Analog trigger control
- Analog stick movement
- Vibration/rumble control
- Controller state management
- Connection management
from unitapi.devices import GamepadDevice
import asyncio
async def main():
# Create a gamepad device
gamepad = GamepadDevice(
device_id='gamepad_01',
name='Virtual Gamepad',
metadata={'controller_type': 'xbox'}
)
# Connect to the gamepad
await gamepad.connect()
# Press buttons
await gamepad.press_button("a")
await gamepad.press_button("b")
# Set trigger values
await gamepad.set_trigger("left_trigger", 0.5)
# Move analog sticks
await gamepad.move_stick("left_stick", 0.5, 0.0) # Move right
# Set vibration/rumble
await gamepad.set_vibration(left_motor=0.7, right_motor=0.3)
# Get current gamepad state
state = await gamepad.get_state()
print(f"Gamepad state: {state}")
# Disconnect when done
await gamepad.disconnect()
asyncio.run(main())
You can create custom device types by inheriting from the BaseDevice
class or one of its subclasses.
from unitapi.devices.base import BaseDevice, DeviceStatus
import asyncio
import logging
class CustomDevice(BaseDevice):
"""Custom device implementation."""
def __init__(self, device_id: str, name: str, metadata=None):
"""Initialize custom device."""
super().__init__(
device_id=device_id,
name=name,
device_type="custom",
metadata=metadata or {}
)
self.logger = logging.getLogger(__name__)
async def connect(self) -> bool:
"""Connect to the device."""
try:
# Custom connection logic
await asyncio.sleep(1) # Simulate connection delay
self.status = DeviceStatus.ONLINE
self.logger.info(f"Device {self.device_id} connected")
return True
except Exception as e:
self.status = DeviceStatus.ERROR
self.logger.error(f"Connection failed: {e}")
return False
async def disconnect(self) -> bool:
"""Disconnect from the device."""
try:
# Custom disconnection logic
await asyncio.sleep(0.5) # Simulate disconnection delay
self.status = DeviceStatus.OFFLINE
self.logger.info(f"Device {self.device_id} disconnected")
return True
except Exception as e:
self.logger.error(f"Disconnection failed: {e}")
return False
async def execute_command(self, command: str, params=None) -> dict:
"""Execute a command on the device."""
try:
if command == "custom_command":
# Implement custom command logic
return {"status": "success", "result": "Custom command executed"}
else:
raise ValueError(f"Unsupported command: {command}")
except Exception as e:
self.logger.error(f"Command execution failed: {e}")
return {"error": str(e)}
from unitapi.devices.base import SensorDevice
import asyncio
import random
import logging
class TemperatureSensor(SensorDevice):
"""Temperature sensor implementation."""
def __init__(self, device_id: str, name: str, metadata=None):
"""Initialize temperature sensor."""
super().__init__(
device_id=device_id,
name=name,
device_type="temperature_sensor",
metadata=metadata or {}
)
self.logger = logging.getLogger(__name__)
self.min_temp = metadata.get("min_temp", 15.0) if metadata else 15.0
self.max_temp = metadata.get("max_temp", 30.0) if metadata else 30.0
async def read_sensor(self) -> dict:
"""Read temperature data."""
try:
# Simulate temperature reading
await asyncio.sleep(0.5)
temperature = random.uniform(self.min_temp, self.max_temp)
return {
"device_id": self.device_id,
"timestamp": asyncio.get_event_loop().time(),
"temperature": round(temperature, 1),
"unit": "°C"
}
except Exception as e:
self.logger.error(f"Sensor reading failed: {e}")
return {"error": str(e)}
Once you've created a device, you need to register it with the UnitAPI server:
from unitapi.core.server import UnitAPIServer
import asyncio
async def main():
# Create a server
server = UnitAPIServer(host='0.0.0.0', port=7890)
# Create a custom device
custom_device = CustomDevice(
device_id='custom_01',
name='My Custom Device',
metadata={'capability': 'custom_function'}
)
# Register the device
server.register_device(
device_id=custom_device.device_id,
device_type=custom_device.type,
metadata=custom_device.metadata
)
# Start the server
await server.start()
asyncio.run(main())
UnitAPI provides a device discovery mechanism that can automatically detect and register devices:
from examples.device_discovery import DeviceDiscoveryService
import asyncio
async def main():
# Create a discovery service
discovery = DeviceDiscoveryService(
server_host='0.0.0.0',
server_port=7890,
discovery_port=7891,
debug=True
)
# Discover devices
devices = await discovery.discover_devices()
print(f"Discovered {len(devices)} devices")
# Start the discovery service
await discovery.start()
asyncio.run(main())
- Asynchronous Operations: Always use
async
/await
for device operations to ensure non-blocking behavior. - Error Handling: Implement proper error handling in all device methods.
- Logging: Use the logging module to provide informative logs for debugging.
- Status Management: Keep the device status updated (
ONLINE
,OFFLINE
,ERROR
,BUSY
). - Resource Cleanup: Ensure proper cleanup in the
disconnect
method. - Metadata: Use metadata to store device-specific configuration and capabilities.
- Command Interface: Implement a consistent command interface through the
execute_command
method.
✍
- Python 3.8+
- pip package manager
pip install unitapi
# Install with MQTT support
pip install unitapi[mqtt]
# Install with WebSocket support
pip install unitapi[websocket]
# Clone the repository
git clone https://github.com/UnitApi/python.git
cd unitapi
# Install dependencies
pip install -r requirements.txt
# Install the package
pip install .
To verify the installation, run:
python -c "import unitapi; print(unitapi.__version__)"
asyncio
pydantic
cryptography
python-jose
paho-mqtt
(for MQTT support)websockets
(for WebSocket support)pyaudio
(for audio device support)opencv-python
(for camera support)
-
Python Version Compatibility
- Ensure you're using Python 3.8 or newer
- Use
python3 -m pip install unitapi
if multiple Python versions are installed
-
Permission Issues
- On Unix-like systems, use
sudo pip install unitapi
- Recommended: Use virtual environments
- On Unix-like systems, use
-
Dependency Conflicts
- Create a virtual environment before installation
python3 -m venv unitapi_env source unitapi_env/bin/activate # On Windows: unitapi_env\Scripts\activate pip install unitapi
-
PyAudio Installation Issues
- On Linux, you may need to install PortAudio development headers:
sudo apt-get install portaudio19-dev pip install pyaudio
- On macOS, you can use Homebrew:
brew install portaudio pip install pyaudio
- On Windows, you might need to install a pre-built wheel:
pip install pipwin pipwin install pyaudio
For contributors and developers:
# Clone the repository
git clone https://github.com/UnitApi/python.git
cd unitapi
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # Activate virtual environment
# Install development dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt
# Install the package in editable mode
pip install -e .
- Ensure
python3-dev
package is installed
sudo apt-get update
sudo apt-get install python3-dev
pip install unitapi
FROM python:3.9-slim
# Install UnitAPI
RUN pip install unitapi
# Optional: Install additional protocol support
RUN pip install unitapi[mqtt,websocket]
# Upgrade to latest version
pip install --upgrade unitapi
# Upgrade with specific protocol support
pip install --upgrade unitapi[mqtt]
pip uninstall unitapi
For installing the Remote Speaker Agent on a remote machine, see the Remote Speaker Agent documentation.
# Install on a remote machine via SSH
scripts/install_remote_speaker_agent_via_ssh.sh remote-host [remote-user]
# Example:
scripts/install_remote_speaker_agent_via_ssh.sh 192.168.1.100 pi
# UnitAPI Protocols [<span style='font-size:20px;'>✍</span>](git@github.com:UnitApi/python/edit/main/docs/protocols.md)
UnitAPI supports multiple communication protocols for device interaction. This document provides detailed information about the built-in protocols and how to implement custom protocols.
## Overview
The protocol layer in UnitAPI provides an abstraction for different communication methods, allowing devices to communicate regardless of the underlying protocol. This enables seamless integration of devices that use different communication standards.
## Built-in Protocols
### 1. WebSocket Protocol
The WebSocket protocol provides real-time, bidirectional communication between clients and servers. It's ideal for applications that require low-latency, high-frequency updates.
#### Features
- Real-time bidirectional communication
- Message-based data exchange
- Support for both client and server roles
- Custom message handlers
#### Example Usage (Client)
```python
from unitapi.protocols.websocket import WebSocketProtocol
import asyncio
async def main():
# Create WebSocket protocol handler
ws_client = WebSocketProtocol(host='localhost', port=8765)
# Connect to WebSocket server
await ws_client.connect()
# Define a message handler
async def handle_temperature_data(data):
print(f"Received temperature: {data}")
# Register the message handler
ws_client.add_message_handler('temperature_data', handle_temperature_data)
# Send a message
await ws_client.send('device_command', {
'device_id': 'sensor_01',
'command': 'read_temperature'
})
# Wait for some time to receive messages
await asyncio.sleep(10)
# Disconnect when done
await ws_client.disconnect()
asyncio.run(main())
from unitapi.protocols.websocket import WebSocketProtocol
import asyncio
async def main():
# Create WebSocket protocol handler
ws_server = WebSocketProtocol(host='0.0.0.0', port=8765)
# Start WebSocket server
await ws_server.create_server()
# The server will handle incoming connections and messages automatically
# based on the internal _handle_client and _process_message methods
asyncio.run(main())
MQTT (Message Queuing Telemetry Transport) is a lightweight publish-subscribe messaging protocol designed for constrained devices and low-bandwidth, high-latency networks. It's ideal for IoT applications.
- Publish-subscribe messaging pattern
- Quality of Service (QoS) levels
- Retained messages
- Last Will and Testament (LWT)
from unitapi.protocols.mqtt import MQTTProtocol
import asyncio
async def main():
# Create MQTT protocol handler
mqtt_client = MQTTProtocol(broker='localhost', port=1883)
# Connect to MQTT broker
await mqtt_client.connect()
# Define a message handler
def handle_temperature_data(topic, payload):
print(f"Received temperature on {topic}: {payload}")
# Subscribe to a topic
await mqtt_client.subscribe('unitapi/devices/+/temperature')
# Register the message handler
mqtt_client.add_message_handler('unitapi/devices/+/temperature', handle_temperature_data)
# Publish a message
await mqtt_client.publish('unitapi/devices/sensor_01/temperature', '22.5')
# Wait for some time to receive messages
await asyncio.sleep(10)
# Disconnect when done
await mqtt_client.disconnect()
asyncio.run(main())
UnitAPI allows you to choose the appropriate protocol based on your application's requirements:
from unitapi.core.server import UnitAPIServer
from unitapi.protocols.websocket import WebSocketProtocol
from unitapi.protocols.mqtt import MQTTProtocol
import asyncio
async def main():
# Create a server
server = UnitAPIServer(host='0.0.0.0', port=7890)
# Create protocol handlers
websocket = WebSocketProtocol(host='0.0.0.0', port=8765)
mqtt = MQTTProtocol(broker='localhost', port=1883)
# Start the server and protocols
server_task = asyncio.create_task(server.start())
websocket_task = asyncio.create_task(websocket.create_server())
# Connect MQTT client
await mqtt.connect()
# Wait for all tasks
await asyncio.gather(server_task, websocket_task)
asyncio.run(main())
You can create custom protocols by implementing the necessary methods for your specific communication needs.
import asyncio
import logging
from typing import Dict, Any, Callable
class CustomProtocol:
"""Custom protocol implementation."""
def __init__(self, host: str, port: int):
"""Initialize custom protocol."""
self.host = host
self.port = port
self.logger = logging.getLogger(__name__)
self._message_handlers = {}
self._connected = False
async def connect(self) -> bool:
"""Connect to the custom protocol server."""
try:
# Implement custom connection logic
await asyncio.sleep(1) # Simulate connection delay
self._connected = True
self.logger.info(f"Connected to {self.host}:{self.port}")
return True
except Exception as e:
self.logger.error(f"Connection failed: {e}")
return False
async def disconnect(self) -> bool:
"""Disconnect from the custom protocol server."""
try:
# Implement custom disconnection logic
await asyncio.sleep(0.5) # Simulate disconnection delay
self._connected = False
self.logger.info(f"Disconnected from {self.host}:{self.port}")
return True
except Exception as e:
self.logger.error(f"Disconnection failed: {e}")
return False
async def send(self, message_type: str, data: Dict[str, Any]) -> bool:
"""Send a message via the custom protocol."""
try:
if not self._connected:
raise ConnectionError("Not connected")
# Implement custom message sending logic
self.logger.info(f"Sending message: {message_type}")
# Simulate message sending
await asyncio.sleep(0.2)
return True
except Exception as e:
self.logger.error(f"Message sending failed: {e}")
return False
def add_message_handler(self, message_type: str, handler: Callable) -> None:
"""Register a handler for specific message types."""
self._message_handlers[message_type] = handler
self.logger.info(f"Registered handler for message type: {message_type}")
async def create_server(self) -> None:
"""Create a server for the custom protocol."""
try:
# Implement custom server creation logic
self.logger.info(f"Starting server on {self.host}:{self.port}")
# Simulate server running
while True:
await asyncio.sleep(1)
except Exception as e:
self.logger.error(f"Server creation failed: {e}")
UnitAPI's protocol abstraction allows devices to communicate regardless of the underlying protocol. This is achieved through a common message format and protocol-specific adapters.
from unitapi.core.server import UnitAPIServer
from unitapi.protocols.websocket import WebSocketProtocol
from unitapi.protocols.mqtt import MQTTProtocol
import asyncio
async def main():
# Create a server
server = UnitAPIServer(host='0.0.0.0', port=7890)
# Create protocol handlers
websocket = WebSocketProtocol(host='0.0.0.0', port=8765)
mqtt = MQTTProtocol(broker='localhost', port=1883)
# Connect protocols
await websocket.connect()
await mqtt.connect()
# Define a message handler that bridges protocols
async def bridge_temperature_data(data):
# When temperature data is received via WebSocket,
# republish it via MQTT
if 'temperature' in data:
device_id = data.get('device_id', 'unknown')
temperature = data.get('temperature')
await mqtt.publish(f'unitapi/devices/{device_id}/temperature', str(temperature))
# Register the bridge handler
websocket.add_message_handler('temperature_data', bridge_temperature_data)
# Start the server
await server.start()
asyncio.run(main())
-
Protocol Selection: Choose the appropriate protocol based on your application's requirements:
- WebSocket for real-time, bidirectional communication
- MQTT for lightweight, publish-subscribe messaging in IoT applications
-
Error Handling: Implement proper error handling for connection, disconnection, and message sending/receiving.
-
Message Handlers: Use message handlers to process incoming messages asynchronously.
-
Connection Management: Ensure proper connection and disconnection to avoid resource leaks.
-
Security: Consider security implications when selecting and implementing protocols:
- Use secure variants (WSS for WebSocket, MQTTS for MQTT)
- Implement authentication and authorization
- Encrypt sensitive data
-
Logging: Use the logging module to provide informative logs for debugging.
-
Asynchronous Operations: Always use
async
/await
for protocol operations to ensure non-blocking behavior.
UnitAPI provides comprehensive security features to protect device communications and ensure proper access control. This document outlines the security mechanisms available in UnitAPI and best practices for securing your applications.
Security is a critical aspect of any IoT or device management system. UnitAPI implements several security layers to protect against unauthorized access, data breaches, and other security threats.
UnitAPI provides a flexible authentication system that supports various authentication methods.
from unitapi.security.authentication import AuthenticationManager
import asyncio
async def main():
# Create authentication manager
auth_manager = AuthenticationManager()
# Register a user
await auth_manager.register_user(
username='admin',
password='secure_password',
roles=['admin', 'user']
)
# Authenticate and get token
token = await auth_manager.authenticate('admin', 'secure_password')
print(f"Authentication token: {token}")
# Verify token
is_valid = await auth_manager.verify_token(token)
print(f"Token is valid: {is_valid}")
# Get user information from token
user_info = await auth_manager.get_user_from_token(token)
print(f"User info: {user_info}")
asyncio.run(main())
from unitapi.core.server import UnitAPIServer
from unitapi.security.authentication import AuthenticationManager
import asyncio
async def main():
# Create server
server = UnitAPIServer(host='0.0.0.0', port=7890)
# Create authentication manager
auth_manager = AuthenticationManager()
# Register users
await auth_manager.register_user('admin', 'admin_password', ['admin'])
await auth_manager.register_user('user', 'user_password', ['user'])
# Set authentication manager for server
server.set_authentication_manager(auth_manager)
# Start server
await server.start()
asyncio.run(main())
from unitapi.core.client import UnitAPIClient
import asyncio
async def main():
# Create client
client = UnitAPIClient(server_host='localhost', server_port=7890)
# Authenticate
token = await client.authenticate('admin', 'admin_password')
# Use token for subsequent requests
client.set_auth_token(token)
# List devices (authenticated request)
devices = await client.list_devices()
print(f"Devices: {devices}")
asyncio.run(main())
UnitAPI implements a role-based access control system that allows fine-grained control over device operations.
from unitapi.security.access_control import AccessControlManager
import asyncio
async def main():
# Create access control manager
acl_manager = AccessControlManager()
# Define static rules
acl_manager.add_rule('admin', 'device:*', 'read:*')
acl_manager.add_rule('admin', 'device:*', 'write:*')
acl_manager.add_rule('user', 'device:sensor', 'read:*')
acl_manager.add_rule('user', 'device:camera', 'read:image')
# Check access
admin_can_write = acl_manager.check_access('admin', 'device:camera', 'write:config')
user_can_read = acl_manager.check_access('user', 'device:sensor', 'read:temperature')
user_cannot_write = not acl_manager.check_access('user', 'device:camera', 'write:config')
print(f"Admin can write camera config: {admin_can_write}")
print(f"User can read sensor temperature: {user_can_read}")
print(f"User cannot write camera config: {user_cannot_write}")
# Define dynamic rule
def temperature_limit_rule(role, resource, action, context):
if resource == 'device:thermostat' and action == 'write:temperature':
# Prevent temperature changes beyond safe limits
temp = context.get('temperature', 0)
return 18 <= temp <= 30
return True
# Add dynamic rule
acl_manager.add_dynamic_rule(temperature_limit_rule)
# Check dynamic rule
safe_temp = acl_manager.check_access(
'user', 'device:thermostat', 'write:temperature',
context={'temperature': 22}
)
unsafe_temp = not acl_manager.check_access(
'user', 'device:thermostat', 'write:temperature',
context={'temperature': 35}
)
print(f"User can set safe temperature: {safe_temp}")
print(f"User cannot set unsafe temperature: {unsafe_temp}")
asyncio.run(main())
from unitapi.core.server import UnitAPIServer
from unitapi.security.authentication import AuthenticationManager
from unitapi.security.access_control import AccessControlManager
import asyncio
async def main():
# Create server
server = UnitAPIServer(host='0.0.0.0', port=7890)
# Create authentication manager
auth_manager = AuthenticationManager()
# Register users
await auth_manager.register_user('admin', 'admin_password', ['admin'])
await auth_manager.register_user('user', 'user_password', ['user'])
# Create access control manager
acl_manager = AccessControlManager()
# Define access rules
acl_manager.add_rule('admin', 'device:*', '*')
acl_manager.add_rule('user', 'device:sensor', 'read:*')
# Set security managers for server
server.set_authentication_manager(auth_manager)
server.set_access_control_manager(acl_manager)
# Start server
await server.start()
asyncio.run(main())
UnitAPI provides encryption utilities to secure sensitive data.
from unitapi.security.encryption import EncryptionManager
import asyncio
async def main():
# Create encryption manager
encryption_manager = EncryptionManager()
# Generate encryption key
key = encryption_manager.generate_key()
# Encrypt data
sensitive_data = "This is sensitive information"
encrypted_data = encryption_manager.encrypt(sensitive_data, key)
print(f"Encrypted data: {encrypted_data}")
# Decrypt data
decrypted_data = encryption_manager.decrypt(encrypted_data, key)
print(f"Decrypted data: {decrypted_data}")
# Secure hash
password = "user_password"
hashed_password = encryption_manager.hash_password(password)
print(f"Hashed password: {hashed_password}")
# Verify password
is_valid = encryption_manager.verify_password(password, hashed_password)
print(f"Password is valid: {is_valid}")
asyncio.run(main())
from unitapi.protocols.websocket import WebSocketProtocol
from unitapi.security.encryption import EncryptionManager
import asyncio
import json
# Create encryption manager
encryption_manager = EncryptionManager()
key = encryption_manager.generate_key()
async def main():
# Create WebSocket protocol handler
ws_client = WebSocketProtocol(host='localhost', port=8765)
# Connect to WebSocket server
await ws_client.connect()
# Define a secure message handler
async def handle_encrypted_data(data):
# Decrypt the received data
encrypted_payload = data.get('payload')
decrypted_payload = encryption_manager.decrypt(encrypted_payload, key)
payload = json.loads(decrypted_payload)
print(f"Received decrypted data: {payload}")
# Register the message handler
ws_client.add_message_handler('encrypted_data', handle_encrypted_data)
# Send an encrypted message
payload = {
'device_id': 'sensor_01',
'command': 'read_temperature',
'timestamp': asyncio.get_event_loop().time()
}
# Encrypt the payload
encrypted_payload = encryption_manager.encrypt(json.dumps(payload), key)
# Send the encrypted message
await ws_client.send('encrypted_data', {
'payload': encrypted_payload
})
# Wait for some time to receive messages
await asyncio.sleep(10)
# Disconnect when done
await ws_client.disconnect()
asyncio.run(main())
UnitAPI includes audit logging capabilities to track security-related events.
from unitapi.security.authentication import AuthenticationManager
from unitapi.security.access_control import AccessControlManager
import logging
import asyncio
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='unitapi_audit.log'
)
async def main():
# Create authentication manager with audit logging
auth_manager = AuthenticationManager(enable_audit=True)
# Register a user
await auth_manager.register_user('admin', 'admin_password', ['admin'])
# Authenticate (this will generate an audit log entry)
token = await auth_manager.authenticate('admin', 'admin_password')
# Failed authentication attempt (this will generate an audit log entry)
try:
await auth_manager.authenticate('admin', 'wrong_password')
except Exception:
pass
# Create access control manager with audit logging
acl_manager = AccessControlManager(enable_audit=True)
# Define access rules
acl_manager.add_rule('admin', 'device:camera', 'read:image')
# Check access (this will generate an audit log entry)
acl_manager.check_access('admin', 'device:camera', 'read:image')
# Denied access attempt (this will generate an audit log entry)
acl_manager.check_access('user', 'device:camera', 'write:config')
asyncio.run(main())
- Always use authentication for production deployments
- Implement role-based access control
- Use strong passwords and consider password policies
- Regularly rotate authentication tokens
- Use encrypted protocols (WSS instead of WS, MQTTS instead of MQTT)
- Encrypt sensitive data before transmission
- Validate and sanitize all input data
- Implement TLS/SSL for all network communications
- Secure device credentials
- Implement device authentication
- Regularly update device firmware
- Monitor device behavior for anomalies
- Enable audit logging
- Regularly review audit logs
- Set up alerts for suspicious activities
- Implement monitoring for security events
- Follow the principle of least privilege
- Secure the server environment
- Keep dependencies updated
- Regularly perform security assessments
Here's a comprehensive example of a secure UnitAPI configuration:
from unitapi.core.server import UnitAPIServer
from unitapi.security.authentication import AuthenticationManager
from unitapi.security.access_control import AccessControlManager
from unitapi.security.encryption import EncryptionManager
from unitapi.protocols.websocket import WebSocketProtocol
import asyncio
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='unitapi_secure.log'
)
async def main():
# Create server
server = UnitAPIServer(host='0.0.0.0', port=7890)
# Create authentication manager
auth_manager = AuthenticationManager(enable_audit=True)
# Register users
await auth_manager.register_user('admin', 'strong_admin_password', ['admin'])
await auth_manager.register_user('operator', 'strong_operator_password', ['operator'])
await auth_manager.register_user('viewer', 'strong_viewer_password', ['viewer'])
# Create access control manager
acl_manager = AccessControlManager(enable_audit=True)
# Define access rules
# Admin can do everything
acl_manager.add_rule('admin', 'device:*', '*')
# Operator can read all devices and control some
acl_manager.add_rule('operator', 'device:*', 'read:*')
acl_manager.add_rule('operator', 'device:sensor', 'write:config')
acl_manager.add_rule('operator', 'device:camera', 'write:config')
# Viewer can only read
acl_manager.add_rule('viewer', 'device:*', 'read:*')
# Create encryption manager
encryption_manager = EncryptionManager()
# Set security managers for server
server.set_authentication_manager(auth_manager)
server.set_access_control_manager(acl_manager)
server.set_encryption_manager(encryption_manager)
# Create secure WebSocket protocol
# In production, use wss:// instead of ws://
websocket = WebSocketProtocol(host='0.0.0.0', port=8765)
# Start the server and protocols
server_task = asyncio.create_task(server.start())
websocket_task = asyncio.create_task(websocket.create_server())
# Wait for all tasks
await asyncio.gather(server_task, websocket_task)
asyncio.run(main())
Security is a critical aspect of any device management system. UnitAPI provides comprehensive security features to protect your devices and data. By following the best practices outlined in this document, you can ensure that your UnitAPI applications are secure and resilient against security threats.
This document describes the SSH tools available in the UnitAPI project for connecting to and managing remote devices.
The UnitAPI project includes Python-based SSH tools that allow for easy connection to remote devices, such as Raspberry Pi, for installation and management of UnitAPI services. These tools provide a more robust and flexible alternative to the bash-based scripts.
A Python implementation of an SSH client with URL-like parameter parsing, similar to the ssh_connect.sh
bash script. This tool provides a simple interface for establishing SSH connections to remote devices.
- URL-like connection format (
user@server
) - Password-based authentication
- Key-based authentication
- Command execution
- Interactive shell
- Verbose logging
python scripts/ssh_connect.py [user@server] [password] [options]
-h, --help
: Show help message-i, --identity FILE
: Specify an identity file for key-based authentication-P, --port PORT
: Specify SSH port (default: 22)-v, --verbose
: Enable verbose SSH output-c, --command CMD
: Execute a command on the remote server
# Connect with password
python scripts/ssh_connect.py pi@192.168.1.100 raspberry
# Connect with identity file
python scripts/ssh_connect.py pi@192.168.1.100 -i ~/.ssh/id_rsa
# Connect with custom port
python scripts/ssh_connect.py admin@server.local mypassword -P 2222
# Execute a command
python scripts/ssh_connect.py pi@192.168.1.100 -c 'ls -la'
A Python implementation of the Remote Keyboard Server installation script. This tool automates the process of installing and configuring the UnitAPI Remote Keyboard Server on a Raspberry Pi.
- SSH connection to Raspberry Pi
- Installation of required packages
- Setup of Python environment
- Configuration of systemd service
- Service management
python scripts/install_remote_keyboard_server.py [options]
--host HOST
: Raspberry Pi host address--user USER
: SSH username (default: pi)--password PASSWORD
: SSH password--port PORT
: SSH port (default: 22)--install-dir DIR
: Installation directory on Raspberry Pi (default: /home/pi/unitapi)--server-port PORT
: UnitAPI server port (default: 7890)--identity FILE
: Path to SSH identity file for key-based authentication--verbose
: Enable verbose output
# Install with password authentication
python scripts/install_remote_keyboard_server.py --host 192.168.1.100 --password raspberry
# Install with key-based authentication
python scripts/install_remote_keyboard_server.py --host 192.168.1.100 --identity ~/.ssh/id_rsa
# Install with custom server port
python scripts/install_remote_keyboard_server.py --host 192.168.1.100 --password raspberry --server-port 8000
A simple example script that demonstrates how to use the SSHConnector class to establish an SSH connection to a remote device and execute commands.
- Connects to a remote device using the SSHConnector class
- Executes a series of system information commands
- Displays the results
- Supports both password and key-based authentication
- Loads connection details from .env file
python examples/ssh_connector_example.py
=== SSH Connection Details ===
Host: 192.168.1.100
User: pi
Password: ********
Port: 22
=============================
Connecting to 192.168.1.100 as pi...
Attempting to connect to 192.168.1.100 as pi...
Using password authentication
Successfully connected to 192.168.1.100
=== System Information ===
Linux raspberrypi 5.15.0-1033-raspi #36-Ubuntu SMP PREEMPT Fri Mar 17 15:20:57 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux
=== Disk Usage ===
Filesystem Size Used Avail Use% Mounted on
/dev/root 29G 5.8G 22G 21% /
...
=== Memory Usage ===
total used free shared buff/cache available
Mem: 3.8Gi 427Mi 2.9Gi 33Mi 511Mi 3.3Gi
Swap: 1.0Gi 0B 1.0Gi
...
Disconnected from remote device
All tools support loading configuration from a .env
file. The following environment variables are recognized:
SSH_USER
: Default SSH usernameSSH_SERVER
: Default SSH server addressSSH_PASSWORD
: Default SSH passwordSSH_PORT
: Default SSH portSSH_IDENTITY_FILE
: Default SSH identity fileSSH_VERBOSE
: Enable verbose output (true/false)
RPI_HOST
: Raspberry Pi host addressRPI_USER
: SSH usernameRPI_PASSWORD
: SSH passwordINSTALL_DIR
: Installation directory on Raspberry PiSERVER_PORT
: UnitAPI server port
These tools require the following Python packages:
paramiko
: SSH implementation for Pythonpython-dotenv
: Loading environment variables from .env files
These dependencies are included in the project's requirements.txt
file.
The Python-based SSH tools offer several advantages over the bash-based scripts:
- Cross-platform compatibility: Works on Windows, macOS, and Linux
- Better error handling: More robust error detection and reporting
- Object-oriented design: Modular and reusable components
- Enhanced security: Better handling of credentials and connections
- Improved maintainability: Easier to extend and modify
Potential future improvements for the SSH tools include:
- Support for SSH tunneling
- Integration with other UnitAPI components
- GUI interface for connection management
- Support for additional authentication methods
- Batch command execution
UnitAPI provides a flexible framework for managing network-connected devices across different protocols and platforms.
- Server: Manages device registration and communication
- Client: Interacts with the server to control devices
- Devices: Represent different types of network peripherals
- Protocols: Support for various communication methods
from unitapi.core.server import UnitAPIServer
# Create a server instance
server = UnitAPIServer(host='localhost', port=7890)
# Register a device
server.register_device(
device_id='temp_sensor_01',
device_type='sensor',
metadata={
'location': 'living_room',
'capabilities': ['temperature', 'humidity']
}
)
# Start the server
server.start()
from unitapi.core.client import UnitAPIClient
# Create a client
client = UnitAPIClient(server_host='localhost', server_port=7890)
# List available devices
devices = client.list_devices()
print("Available Devices:", devices)
# List specific device type
sensor_devices = client.list_devices(device_type='sensor')
print("Sensor Devices:", sensor_devices)
from unitapi.devices.camera import CameraDevice
import asyncio
# Create a camera device
camera = CameraDevice(
device_id='camera_01',
name='Main Camera',
metadata={
'resolution': '1080p',
'fps': 30,
'location': 'front_door'
}
)
# Connect to the camera
await camera.connect()
# Capture an image
image_data = await camera.capture_image()
print(f"Image captured: {image_data}")
# Start a video stream
stream_info = await camera.start_video_stream(duration=10)
print(f"Stream started: {stream_info}")
from unitapi.devices.microphone import MicrophoneDevice
import asyncio
# Create a microphone device
mic = MicrophoneDevice(
device_id='mic_01',
name='Desktop Microphone',
metadata={
'sample_rate': 44100,
'channels': 2,
'location': 'office'
}
)
# Connect to the microphone
await mic.connect()
# Record audio
audio_data = await mic.record_audio(duration=5, sample_rate=44100)
print(f"Audio recorded: {audio_data}")
from unitapi.devices.gpio import GPIODevice
import asyncio
# Create GPIO device
gpio = GPIODevice(
device_id='rpi_gpio_01',
name='Raspberry Pi GPIO',
metadata={'total_pins': 40}
)
# Connect to the GPIO device
await gpio.connect()
# Set pin mode and control
await gpio.set_pin_mode(18, 'output')
await gpio.digital_write(18, True)
# Read from a pin
await gpio.set_pin_mode(17, 'input')
pin_value = await gpio.digital_read(17)
print(f"Pin 17 value: {pin_value}")
# PWM control
await gpio.set_pin_mode(12, 'output')
await gpio.pwm_write(12, 0.5) # 50% duty cycle
UnitAPI provides a comprehensive device discovery mechanism that can detect devices on the local network and on the local machine.
from examples.device_discovery import DeviceDiscoveryService
import asyncio
# Create a discovery service
discovery = DeviceDiscoveryService(
server_host='0.0.0.0',
server_port=7890,
discovery_port=7891,
debug=True
)
# Discover devices
devices = await discovery.discover_devices()
print(f"Discovered {len(devices)} devices")
# Start the discovery service
await discovery.start()
UnitAPI includes a Remote Speaker Agent that allows you to control speakers on a remote machine. See the Remote Speaker Agent documentation for details.
# Connect to a remote speaker agent
from unitapi.core.client import UnitAPIClient
import asyncio
# Create a client
client = UnitAPIClient(server_host='remote-host', server_port=7890)
# List available speakers
speakers = await client.list_devices(device_type='speaker')
print("Available Speakers:", speakers)
# Play audio on a specific speaker
await client.execute_command(
device_id='speaker_01',
command='play_audio',
params={
'file': 'path/to/audio.wav'
}
)
from unitapi.security.authentication import AuthenticationManager
# Create authentication manager
auth_manager = AuthenticationManager()
# Register a user
await auth_manager.register_user(
username='admin',
password='secure_password',
roles=['admin', 'user']
)
# Authenticate
token = await auth_manager.authenticate('admin', 'secure_password')
from unitapi.protocols.websocket import WebSocketProtocol
import asyncio
# Create WebSocket protocol handler
ws_client = WebSocketProtocol(host='localhost', port=8765)
# Connect and send message
await ws_client.connect()
await ws_client.send('device_command', {
'device_id': 'sensor_01',
'command': 'read_temperature'
})
# Add a message handler
async def handle_temperature_data(data):
print(f"Received temperature: {data}")
ws_client.add_message_handler('temperature_data', handle_temperature_data)
# Disconnect when done
await ws_client.disconnect()
from unitapi.protocols.mqtt import MQTTProtocol
import asyncio
# Create MQTT protocol handler
mqtt_client = MQTTProtocol(broker='localhost', port=1883)
# Connect and publish
await mqtt_client.connect()
await mqtt_client.publish('unitapi/devices/temperature', '22.5')
# Subscribe to a topic
await mqtt_client.subscribe('unitapi/devices/+/status')
# Add a message handler
def handle_status_message(topic, payload):
print(f"Received status on {topic}: {payload}")
mqtt_client.add_message_handler('unitapi/devices/+/status', handle_status_message)
UnitAPI includes Docker examples that demonstrate how to containerize UnitAPI applications. See the Docker example README for details.
# Navigate to the docker example directory
cd examples/docker
# Start the containers
docker-compose up -d
# Access the client container
docker exec -it unitapi-speaker-client bash
try:
# Device operations
await device.connect()
data = await device.read_sensor()
except Exception as e:
# Handle connection or read errors
print(f"Device error: {e}")
- Always use async/await for device operations
- Implement proper error handling
- Use authentication and access control
- Keep sensitive information secure
- Monitor device states and connections
- Use device discovery for automatic setup
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
You can easily extend UnitAPI by:
- Creating custom device types
- Implementing new protocol handlers
- Adding dynamic access rules
- Integrating with existing systems
✍
This directory contains examples for controlling a camera (webcam) on a PC using UnitAPI. These examples demonstrate how to capture images, record videos, and control the camera remotely.
camera_client.py
: Client that demonstrates local camera capturecamera_frame_client.py
: Client that demonstrates capturing individual frames from the cameracamera_server.py
: Server that exposes camera functionality through UnitAPIremote_camera_client.py
: Client that connects to a remote camera serverremote_camera_frame_client.py
: Client that captures frames from a remote camerascreenshot_client.py
: Client that demonstrates taking screenshots
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - OpenCV installed (
pip install opencv-python
) - NumPy installed (
pip install numpy
)
The camera client examples demonstrate how to use the camera device locally to capture images and record videos.
# Capture images from the camera
python examples/pc/camera/camera_client.py
# Capture frames from the camera
python examples/pc/camera/camera_frame_client.py
# Take screenshots
python examples/pc/camera/screenshot_client.py
These examples demonstrate:
- Creating a camera device
- Capturing images with different resolutions and formats
- Applying image effects
- Capturing video frames
- Taking screenshots of the desktop
The camera server and remote client examples demonstrate how to control a camera remotely using UnitAPI.
# Run on the PC with the camera you want to access remotely
python examples/pc/camera/camera_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging
# Capture images from a remote camera
python examples/pc/camera/remote_camera_client.py --host 192.168.1.100 --port 7890
# Capture frames from a remote camera
python examples/pc/camera/remote_camera_frame_client.py --host 192.168.1.100 --port 7890
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--width
: Image width (default: 1280)--height
: Image height (default: 720)--format
: Image format (default: jpeg)--quality
: Image quality (default: 90)--effect
: Image effect to apply (e.g., grayscale, negative, sketch)
The camera examples support the following operations:
- Capture Image: Capture a single image from the camera
- Capture Frame: Capture a video frame from the camera
- Record Video: Record video from the camera
- Take Screenshot: Capture the current screen contents
- Apply Effects: Apply visual effects to captured images
The camera functionality can be integrated with other applications:
- Computer vision applications
- Video conferencing
- Security monitoring
- Automated testing with visual verification
- Image processing pipelines
Remote camera control provides powerful capabilities but also introduces security risks. Consider the following:
- Run the server on a secure, private network
- Use UnitAPI's authentication and encryption features
- Be cautious about allowing remote camera control in sensitive environments
- Consider implementing additional access controls based on your specific requirements
- Camera Access Issues: Ensure the camera is not being used by another application
- Permission Issues: Some systems may require additional permissions for camera access
- Performance Issues: Adjust resolution and frame rate for better performance
- Format Compatibility: Ensure the image format is supported by your system
- Remote Monitoring: Monitor a location using a remote camera
- Computer Vision: Develop computer vision applications with remote camera input
- Automated Testing: Capture screenshots for visual regression testing
- Video Recording: Record video for documentation or tutorials
- Security: Create a simple security camera system
This directory contains examples for controlling a keyboard on a PC using UnitAPI. These examples demonstrate how to use the keyboard device locally and how to set up a keyboard server for remote control.
keyboard_client.py
: Client that demonstrates local keyboard controlkeyboard_server.py
: Server that exposes keyboard functionality through UnitAPIremote_keyboard_client.py
: Client that connects to the server and controls the keyboard remotely
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAutoGUI installed (
pip install pyautogui
) - python-dotenv (for remote control example)
The keyboard client demonstrates how to use the keyboard device locally to type text, press keys, and use keyboard shortcuts.
# Run the local keyboard example
python examples/pc/keyboard/keyboard_client.py
This example demonstrates:
- Creating a keyboard device
- Typing text
- Pressing individual keys
- Using keyboard shortcuts
- Handling special keys
The keyboard server and remote client demonstrate how to control a keyboard remotely using UnitAPI.
# Run on the PC you want to control
python examples/pc/keyboard/keyboard_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--device-id
: Custom keyboard device ID (default: keyboard_01)--name
: Custom keyboard device name (default: Raspberry Pi Keyboard)
# Connect to a local server
python examples/pc/keyboard/remote_keyboard_client.py --demo typing
# Connect to a remote PC
python examples/pc/keyboard/remote_keyboard_client.py --host 192.168.1.100 --port 7890 --demo all
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--list
: List available remote keyboards--device-id
: Specific remote keyboard device ID to use--text
: Text to type on the remote keyboard--key
: Key to press on the remote keyboard--hotkey
: Hotkey to press (comma-separated keys, e.g., ctrl,s)
The remote client provides several demo modes:
- Typing Demo: Demonstrates typing text and pressing Enter
- Hotkey Demo: Demonstrates using keyboard shortcuts like Ctrl+A
- Key Sequence Demo: Demonstrates using arrow keys and modifier keys
- All Demos: Runs all demos in sequence
The keyboard examples support the following operations:
- Key Down: Press and hold a key
- Key Up: Release a key
- Press Key: Press and release a key
- Type Text: Type a sequence of characters
- Press Hotkey: Press a combination of keys simultaneously
- Release All Keys: Release all currently pressed keys
The keyboard functionality can be integrated with other applications:
- Control text editors or command-line interfaces
- Automate form filling in web browsers
- Control games or other applications
- Implement custom keyboard shortcuts for specific tasks
Remote keyboard control provides powerful capabilities but also introduces security risks. Consider the following:
- Run the server on a secure, private network
- Use UnitAPI's authentication and encryption features
- Be cautious about allowing remote keyboard control in sensitive environments
- Consider implementing additional access controls based on your specific requirements
- Connection Issues: Ensure the server is running and accessible from the client's network
- Permission Issues: Some systems may require additional permissions for keyboard control
- Key Mapping Issues: Different keyboard layouts may require adjustments to key mappings
- Stuck Keys: If keys appear to be stuck, use the
release_all_keys
command to reset the keyboard state
- Remote Control: Control applications on a headless PC
- Automation: Automate repetitive keyboard tasks
- Kiosk Systems: Implement controlled keyboard input for kiosk applications
- Accessibility: Create custom keyboard interfaces for accessibility purposes
This directory contains scripts for controlling a keyboard on a remote Raspberry Pi device.
The Remote Keyboard Control system allows you to send keyboard commands from your computer to a Raspberry Pi over the network. This can be useful for:
- Remote control of Raspberry Pi applications
- Automation of keyboard input for testing
- Controlling devices without direct physical access
- Creating interactive demos and presentations
The system consists of two main components:
- Server (
remote_keyboard_server.py
): Runs on the Raspberry Pi and registers a keyboard device with the UnitAPI server. - Client (
remote_keyboard_control_fixed.py
): Runs on your computer and sends keyboard commands to the server.
Use the installation script to set up the server on your Raspberry Pi:
./scripts/install_remote_keyboard_server_fixed.sh --host <raspberry_pi_ip> --password <raspberry_pi_password>
This script will:
- Copy the necessary files to the Raspberry Pi
- Install required dependencies
- Set up a systemd service to run the server automatically
For detailed installation instructions, see Remote Keyboard Server Installation Guide.
- Update your
.env
file with the Raspberry Pi connection details:
RPI_HOST=192.168.1.100 # Replace with your Raspberry Pi's IP address
RPI_USER=pi # Replace with your Raspberry Pi username
RPI_PASSWORD=raspberry # Replace with your Raspberry Pi password
- Make sure you have the required Python packages installed:
pip install -r requirements.txt
To check the connection to the Raspberry Pi:
python examples/remote_keyboard_control_fixed.py --check-connection
To list available keyboard devices on the Raspberry Pi:
python examples/remote_keyboard_control_fixed.py --list
To type text on the remote keyboard:
python examples/remote_keyboard_control_fixed.py --device-id keyboard_01 --text "Hello, world!"
To press a specific key:
python examples/remote_keyboard_control_fixed.py --device-id keyboard_01 --key enter
To press a hotkey combination:
python examples/remote_keyboard_control_fixed.py --device-id keyboard_01 --hotkey ctrl,a
To run a demo sequence that demonstrates various keyboard actions:
python examples/remote_keyboard_control_fixed.py
This will:
- List available keyboards on the Raspberry Pi
- Type some text
- Press Enter
- Type more text
- Press Ctrl+A to select all text
If you're having trouble connecting to the Raspberry Pi:
- Check that the Raspberry Pi is powered on and connected to the network
- Verify that the IP address in your
.env
file is correct - Make sure the UnitAPI server is running on the Raspberry Pi
- Check the server status:
python scripts/ssh_connect_wrapper.sh <username>@<raspberry_pi_ip> <password> -c 'systemctl status unitapi-keyboard.service'
If the script is controlling your local keyboard instead of the remote one:
- Make sure you're using the fixed version of the client script (
remote_keyboard_control_fixed.py
) - Check that the connection to the remote server is successful
- Verify that the keyboard device is registered on the remote server
You can specify a custom keyboard device ID and name when starting the server:
python examples/remote_keyboard_server.py --device-id custom_keyboard --name "My Custom Keyboard"
You can run multiple instances of the server with different device IDs to control multiple keyboards:
python examples/remote_keyboard_server.py --device-id keyboard_01 --port 7890
python examples/remote_keyboard_server.py --device-id keyboard_02 --port 7891
- The remote keyboard control system does not include authentication by default
- Consider running the server on a private network
- Use SSH tunneling for secure remote access
- Be cautious when allowing remote keyboard control, as it can potentially execute commands on the Raspberry Pi
This example demonstrates how to control a keyboard on a remote Raspberry Pi device using UnitAPI. The script uses connection details (host, username, password) from a .env
file.
- A Raspberry Pi with UnitAPI server installed and running
- Python 3.6+ on both the client and Raspberry Pi
- Required Python packages:
unitapi
python-dotenv
-
Make sure the UnitAPI server is running on your Raspberry Pi
-
Update the
.env
file with your Raspberry Pi connection details:RPI_HOST=192.168.1.100 # Replace with your Raspberry Pi's IP address RPI_USER=pi # Replace with your Raspberry Pi username RPI_PASSWORD=raspberry # Replace with your Raspberry Pi password
-
Make sure the keyboard device is registered on the Raspberry Pi UnitAPI server
python examples/remote_keyboard_control.py --list
python examples/remote_keyboard_control.py --device-id keyboard_01 --text "Hello, world!"
python examples/remote_keyboard_control.py --device-id keyboard_01 --key "enter"
python examples/remote_keyboard_control.py --device-id keyboard_01 --hotkey "ctrl,a"
If no specific action is provided, the script will run a demo sequence on the first available keyboard:
python examples/remote_keyboard_control.py
If no keyboards are found, make sure:
- The UnitAPI server is running on your Raspberry Pi
- The keyboard device is registered with the server
- The connection details in the
.env
file are correct - There are no network issues preventing connection to the Raspberry Pi
You can start the device discovery service on the Raspberry Pi with:
python examples/device_discovery.py
- The script loads connection details from the
.env
file - It connects to the UnitAPI server on the Raspberry Pi
- It lists available keyboard devices or performs the specified action
- Commands are sent to the remote keyboard device through the UnitAPI client
The script demonstrates:
- Connecting to a remote UnitAPI server
- Listing available devices
- Typing text on a remote keyboard
- Pressing keys and hotkey combinations
- Using environment variables for configuration
This directory contains examples for controlling a microphone on a PC using UnitAPI. These examples demonstrate how to record audio, measure audio levels, and control the microphone remotely.
microphone_recording_client.py
: Client that demonstrates local microphone recordingmicrophone_input_client.py
: Client that demonstrates capturing audio input from the microphonemicrophone_server.py
: Server that exposes microphone functionality through UnitAPI for remote control
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAudio installed (
pip install pyaudio
) - NumPy installed (
pip install numpy
) - FFmpeg (optional, for non-WAV audio formats)
The microphone client examples demonstrate how to use the microphone device locally to record audio and capture audio input.
# Record audio from the microphone
python examples/pc/microphone/microphone_recording_client.py
# Capture audio input from the microphone
python examples/pc/microphone/microphone_input_client.py
These examples demonstrate:
- Creating a microphone device
- Recording audio with different sample rates and formats
- Measuring audio input levels
- Processing audio data in real-time
The microphone server allows remote clients to control the microphone on a PC using UnitAPI.
# Run on the PC with the microphone you want to access remotely
python examples/pc/microphone/microphone_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging
You can connect to the microphone server using the UnitAPI client:
from unitapi.core.client import UnitAPIClient
async def control_remote_microphone():
# Connect to the server
client = UnitAPIClient(server_host="192.168.1.100", server_port=7890)
# List available devices
devices = await client.list_devices()
# Find the microphone device
mic_devices = [d for d in devices if d.get('type') == 'microphone']
if not mic_devices:
print("No microphone devices found")
return
mic_device = mic_devices[0]
device_id = mic_device.get('device_id')
# Start recording
result = await client.execute_command(
device_id=device_id,
command="start_recording",
params={
"sample_rate": 44100,
"channels": 1,
"format": "wav",
"output_file": "remote_recording.wav",
"duration": 10 # Record for 10 seconds
}
)
recording_id = result.get('recording_id')
# Get audio level
level_result = await client.execute_command(
device_id=device_id,
command="get_audio_level",
params={}
)
print(f"Audio level: {level_result.get('level')}")
# Wait for recording to complete
await asyncio.sleep(10)
# Stop recording manually if no duration was specified
# await client.execute_command(
# device_id=device_id,
# command="stop_recording",
# params={"recording_id": recording_id}
# )
The microphone examples support the following operations:
- Start Recording: Start recording audio from the microphone
- Stop Recording: Stop an active recording
- Get Audio Level: Measure the current audio input level
- Process Audio: Process audio data in real-time
The examples support various audio formats:
- WAV: Uncompressed audio (default)
- MP3: Compressed audio (requires FFmpeg)
- Other formats supported by FFmpeg
The microphone functionality can be integrated with other applications:
- Speech recognition systems
- Audio processing pipelines
- Voice assistants
- Audio visualization tools
- Sound detection and monitoring
Remote microphone control provides powerful capabilities but also introduces security risks. Consider the following:
- Run the server on a secure, private network
- Use UnitAPI's authentication and encryption features
- Be cautious about allowing remote microphone control in sensitive environments
- Consider implementing additional access controls based on your specific requirements
- Microphone Access Issues: Ensure the microphone is not being used by another application
- Permission Issues: Some systems may require additional permissions for microphone access
- PyAudio Installation: On some systems, PyAudio may require additional dependencies
- FFmpeg Missing: For non-WAV formats, ensure FFmpeg is installed and available in the system path
- Voice Recording: Record voice for documentation or dictation
- Audio Monitoring: Monitor audio levels in an environment
- Speech Recognition: Capture audio for speech-to-text processing
- Sound Detection: Detect specific sounds or noise levels
- Remote Conferencing: Implement remote audio capture for conferencing applications
This directory contains miscellaneous examples for UnitAPI that don't fit into the specific device categories. These examples demonstrate various features and capabilities of UnitAPI.
device_discovery.py
: Example demonstrating how to discover UnitAPI devices on the networkssh_connector.py
: Example demonstrating how to connect to remote devices using SSHinput_devices.py
: Example demonstrating how to work with multiple input devices
The device discovery example shows how to find UnitAPI devices on the network. This is useful for discovering available devices without knowing their specific addresses.
# Run the device discovery example
python examples/pc/misc/device_discovery.py
This example demonstrates:
- Setting up a discovery service
- Broadcasting device availability
- Discovering devices on the network
- Handling device discovery events
The SSH connector example shows how to connect to remote devices using SSH. This is useful for securely connecting to and controlling devices on remote machines.
# Run the SSH connector example
python examples/pc/misc/ssh_connector.py --host remote-host --user username
Options:
--host
: Remote host to connect to--user
: Username for SSH authentication--password
: Password for SSH authentication (or use key-based authentication)--port
: SSH port (default: 22)
This example demonstrates:
- Establishing SSH connections
- Executing commands on remote machines
- Transferring files securely
- Managing remote sessions
The input devices example shows how to work with multiple input devices simultaneously. This is useful for applications that need to handle input from various sources.
# Run the input devices example
python examples/pc/misc/input_devices.py
This example demonstrates:
- Creating multiple input devices
- Handling input from different sources
- Coordinating input events
- Managing device lifecycles
These miscellaneous examples can be combined with the device-specific examples to create more complex applications. For example:
- Use device discovery to find available devices
- Connect to remote devices using SSH
- Control specific devices using the device-specific examples
For more information about UnitAPI and its capabilities, see the documentation in the docs/
directory.
This directory contains examples for controlling a mouse on a PC using UnitAPI. These examples demonstrate how to use the mouse device locally and how to set up a mouse server for remote control.
mouse_client.py
: Client that demonstrates local mouse controlmouse_pyautogui_client.py
: Client that demonstrates mouse control using PyAutoGUImouse_server.py
: Server that exposes mouse functionality through UnitAPI for remote control
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAutoGUI installed (
pip install pyautogui
)
The mouse client demonstrates how to use the mouse device locally to move the cursor, click, and perform other mouse operations.
# Run the standard mouse example
python examples/pc/mouse/mouse_client.py
# Run the PyAutoGUI mouse example
python examples/pc/mouse/mouse_pyautogui_client.py
These examples demonstrate:
- Creating a mouse device
- Moving the mouse cursor to absolute positions
- Moving the mouse cursor relatively
- Clicking and double-clicking
- Pressing and releasing mouse buttons
- Scrolling
- Dragging objects
The mouse server allows remote clients to control the mouse on a PC using UnitAPI.
# Run on the PC you want to control
python examples/pc/mouse/mouse_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--device-id
: Custom mouse device ID (default: mouse_01)--name
: Custom mouse device name (default: PC Mouse)
You can connect to the mouse server using the UnitAPI client:
from unitapi.core.client import UnitAPIClient
async def control_remote_mouse():
# Connect to the server
client = UnitAPIClient(server_host="192.168.1.100", server_port=7890)
# List available devices
devices = await client.list_devices()
# Find the mouse device
mouse_devices = [d for d in devices if d.get('type') == 'mouse']
if not mouse_devices:
print("No mouse devices found")
return
mouse_device = mouse_devices[0]
device_id = mouse_device.get('device_id')
# Move the mouse
await client.execute_command(
device_id=device_id,
command="move_to",
params={"x": 500, "y": 500}
)
# Click the mouse
await client.execute_command(
device_id=device_id,
command="click",
params={"button": "left"}
)
The mouse examples support the following operations:
- Move To: Move the mouse cursor to an absolute position
- Move Relative: Move the mouse cursor by a relative amount
- Click: Click a mouse button
- Double Click: Double-click a mouse button
- Button Down: Press and hold a mouse button
- Button Up: Release a mouse button
- Scroll: Scroll the mouse wheel
- Drag: Drag the mouse from the current position to a new position
The mouse functionality can be integrated with other applications:
- Control GUI applications remotely
- Automate repetitive mouse tasks
- Create custom mouse interfaces for accessibility purposes
- Implement remote desktop functionality
- Create automated testing tools
Remote mouse control provides powerful capabilities but also introduces security risks. Consider the following:
- Run the server on a secure, private network
- Use UnitAPI's authentication and encryption features
- Be cautious about allowing remote mouse control in sensitive environments
- Consider implementing additional access controls based on your specific requirements
- Connection Issues: Ensure the server is running and accessible from the client's network
- Permission Issues: Some systems may require additional permissions for mouse control
- Coordinate Issues: Screen resolutions may differ between systems, affecting absolute positioning
- Performance Issues: High latency networks may affect the responsiveness of mouse control
- Remote Control: Control applications on a headless PC
- Automation: Automate repetitive mouse tasks
- Kiosk Systems: Implement controlled mouse input for kiosk applications
- Accessibility: Create custom mouse interfaces for accessibility purposes
- Testing: Automate GUI testing with programmatic mouse control
This directory contains examples for using UnitAPI with various devices on a PC. These examples demonstrate how to control and interact with different hardware devices, both locally and remotely.
camera/
: Examples for controlling webcams and capturing images/videoskeyboard/
: Examples for controlling keyboards and sending keystrokesmicrophone/
: Examples for recording audio and processing microphone inputmouse/
: Examples for controlling mouse movements and clicksspeaker/
: Examples for playing audio and controlling speakersmisc/
: Miscellaneous examples that don't fit into the other categories
Each subdirectory contains examples for a specific device type:
The camera/
directory contains examples for working with webcams and other camera devices. These examples demonstrate how to capture images, record videos, and process camera frames.
The keyboard/
directory contains examples for working with keyboards. These examples demonstrate how to send keystrokes, handle keyboard events, and control keyboards remotely.
The microphone/
directory contains examples for working with microphones. These examples demonstrate how to record audio, process microphone input, and measure audio levels.
The mouse/
directory contains examples for working with mice. These examples demonstrate how to control mouse movements, handle mouse clicks, and automate mouse actions.
The speaker/
directory contains examples for working with speakers. These examples demonstrate how to play audio files, generate sounds, and control audio playback.
Many examples follow a client-server architecture:
- Server: Runs on the device you want to control and exposes its functionality through UnitAPI
- Client: Connects to the server and controls the device remotely
This architecture allows you to:
- Control devices on remote machines
- Create distributed applications
- Implement device sharing and remote access
- Build automation systems that span multiple devices
Each subdirectory contains its own README.md file with specific instructions for running the examples. In general, you can run the examples using Python:
# Run a client example
python examples/pc/device_type/example_client.py
# Run a server example
python examples/pc/device_type/example_server.py --host 0.0.0.0 --port 7890
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - Device-specific dependencies (see individual README files)
Most server examples support the following command-line options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging
Most client examples support:
--host
: Server host to connect to (default: localhost)--port
: Server port to connect to (default: 7890)--debug
: Enable debug logging
When running servers that expose device functionality, consider the following security practices:
- Run servers on secure, private networks
- Use UnitAPI's authentication and encryption features
- Implement appropriate access controls
- Be cautious about exposing sensitive devices to remote access
For more information about UnitAPI and its capabilities, see the documentation in the docs/
directory.
This directory contains examples for controlling speakers on a PC using UnitAPI. These examples demonstrate how to play audio files, generate sounds, and control speakers remotely.
speaker_client.py
: Client that demonstrates basic speaker controlspeaker_playback.py
: Client that demonstrates playing audio filesspeaker_audio_playback.py
: Client that demonstrates advanced audio playback featuresspeaker_playback_fixed.py
: Fixed version of the playback example with improved error handlingspeaker_audio_playback_fixed.py
: Fixed version of the audio playback example with improved error handlingspeaker_server.py
: Server that exposes speaker functionality through UnitAPI for remote control
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAudio installed (
pip install pyaudio
) - NumPy installed (
pip install numpy
)
The speaker client examples demonstrate how to use the speaker device locally to play audio files and generate sounds.
# Basic speaker control
python examples/pc/speaker/speaker_client.py
# Play audio files
python examples/pc/speaker/speaker_playback.py --file path/to/audio.wav
# Advanced audio playback
python examples/pc/speaker/speaker_audio_playback.py --file path/to/audio.wav
# Fixed versions with improved error handling
python examples/pc/speaker/speaker_playback_fixed.py --file path/to/audio.wav
python examples/pc/speaker/speaker_audio_playback_fixed.py --file path/to/audio.wav
These examples demonstrate:
- Creating a speaker device
- Playing audio files in various formats
- Controlling volume and playback speed
- Generating tones and sounds
- Error handling and resource management
The speaker server allows remote clients to control the speakers on a PC using UnitAPI.
# Run on the PC with the speakers you want to access remotely
python examples/pc/speaker/speaker_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging
You can connect to the speaker server using the UnitAPI client:
from unitapi.core.client import UnitAPIClient
async def control_remote_speaker():
# Connect to the server
client = UnitAPIClient(server_host="192.168.1.100", server_port=7890)
# List available devices
devices = await client.list_devices()
# Find the speaker device
speaker_devices = [d for d in devices if d.get('type') == 'speaker']
if not speaker_devices:
print("No speaker devices found")
return
speaker_device = speaker_devices[0]
device_id = speaker_device.get('device_id')
# Play audio file
await client.execute_command(
device_id=device_id,
command="play_audio",
params={
"file_path": "path/to/audio.wav",
"volume": 0.8
}
)
# Generate a tone
await client.execute_command(
device_id=device_id,
command="play_tone",
params={
"frequency": 440, # A4 note
"duration": 1.0, # 1 second
"volume": 0.5
}
)
The examples support various audio formats:
- WAV: Uncompressed audio (default)
- MP3: Compressed audio (requires additional libraries)
- OGG: Compressed audio (requires additional libraries)
- Other formats supported by the system's audio libraries
The speaker functionality can be integrated with other applications:
- Text-to-speech systems
- Music players
- Notification systems
- Audio visualization tools
- Interactive applications and games
- Audio Device Issues: Ensure the audio device is properly configured and not in use by another application
- Format Support: Some audio formats may require additional libraries
- PyAudio Installation: On some systems, PyAudio may require additional dependencies
- Volume Control: If no sound is heard, check system volume and application volume settings
- Audio Playback: Play music or sound effects in applications
- Text-to-Speech: Convert text to speech for accessibility
- Notifications: Play alert sounds for system events
- Remote Control: Control audio playback on a remote system
- Sound Generation: Generate tones and sounds for testing or musical applications
The UnitAPI Remote Speaker Agent allows you to manage and control speakers on a remote PC via SSH. This document explains how to install, configure, and use this feature.
The Remote Speaker Agent is a service that runs on a remote machine and provides access to all speakers on that machine through the UnitAPI protocol. This allows you to:
- Discover all speakers on the remote machine
- Play audio on specific speakers
- Test speakers with test tones
- Stream audio from one machine to speakers on another
There are two ways to install the Remote Speaker Agent:
If you have direct access to the remote machine, you can install the agent directly:
# Log in to the remote machine
ssh user@remote-host
# Clone the UnitAPI repository (if not already done)
git clone https://github.com/UnitApi/python.git
cd UnitApi/python
# Run the installation script
sudo scripts/install_remote_speaker_agent.sh
If you only have SSH access to the remote machine, you can install the agent remotely from your local machine:
# Clone the UnitAPI repository (if not already done)
git clone https://github.com/UnitApi/python.git
cd UnitApi/python
# Run the remote installation script
scripts/install_remote_speaker_agent_via_ssh.sh remote-host [remote-user]
# Example:
scripts/install_remote_speaker_agent_via_ssh.sh 192.168.1.100 pi
The remote installation script will:
- Connect to the remote machine via SSH
- Copy the installation script to the remote machine
- Execute the installation script on the remote machine
- Create a local client script for testing the remote speakers
After installation, you can manage the Remote Speaker Agent on the remote machine using the following commands:
# List all available speakers
ssh user@remote-host 'sudo unitapi-speaker --list'
# Test all speakers
ssh user@remote-host 'sudo unitapi-speaker --test'
# Check the service status
ssh user@remote-host 'sudo unitapi-speaker --status'
# Start the service
ssh user@remote-host 'sudo unitapi-speaker --start'
# Stop the service
ssh user@remote-host 'sudo unitapi-speaker --stop'
# Enable the service to start at boot
ssh user@remote-host 'sudo unitapi-speaker --enable'
# Disable the service from starting at boot
ssh user@remote-host 'sudo unitapi-speaker --disable'
To connect to the Remote Speaker Agent from another machine, you can use the UnitAPI client:
from unitapi.core.client import UnitAPIClient
import asyncio
async def main():
# Create a client
client = UnitAPIClient(server_host='remote-host', server_port=7890)
# List available speakers
devices = await client.list_devices(device_type='speaker')
print("Available Speakers:", devices)
# Play audio on a specific speaker
await client.execute_command(
device_id='speaker_01',
command='play_audio',
params={
'file': 'path/to/audio.wav'
}
)
# Run the async function
asyncio.run(main())
If you used the remote installation script, a client script was created for you:
# List all available speakers
python remote_speaker_client.py --host remote-host --list
# Test all speakers
python remote_speaker_client.py --host remote-host --test
# Test a specific speaker
python remote_speaker_client.py --host remote-host --device speaker_id
# Play an audio file on a specific speaker
python remote_speaker_client.py --host remote-host --device speaker_id --file path/to/audio.wav
# Play a test tone with custom frequency and duration
python remote_speaker_client.py --host remote-host --device speaker_id --frequency 880 --duration 2.0
UnitAPI includes a Docker Compose example that demonstrates how to set up a virtual speaker server on one machine and a client on another machine using Docker. This example simulates the process of installing the UnitAPI speaker agent on a remote PC and controlling its speakers.
To use this example:
# Navigate to the docker example directory
cd examples/docker
# Start the containers
docker-compose up -d
# View the logs
docker-compose logs -f
# Access the client container and test the speakers
docker exec -it unitapi-speaker-client bash
python /opt/unitapi/client.py --host 172.28.1.2 --list
python /opt/unitapi/client.py --host 172.28.1.2 --test
For more details, see the Docker example README.
The Remote Speaker Agent consists of the following components:
- UnitAPI Server: Handles device registration and communication
- WebSocket Server: Provides a WebSocket interface for real-time communication
- Speaker Detection: Automatically detects all speakers on the system
- Speaker Registry: Maintains a registry of all available speakers
- Configuration: Stores speaker configuration in
/etc/unitapi/speaker_agent.json
- Systemd Service: Runs the agent as a system service (
unitapi-speaker-agent
)
The agent is installed in /opt/unitapi
and runs in a Python virtual environment to avoid conflicts with system packages.
If you encounter issues with the Remote Speaker Agent, check the following:
-
Service Status: Check if the service is running
ssh user@remote-host 'sudo systemctl status unitapi-speaker-agent'
-
Logs: Check the service logs
ssh user@remote-host 'sudo journalctl -u unitapi-speaker-agent'
-
Configuration: Check the configuration file
ssh user@remote-host 'sudo cat /etc/unitapi/speaker_agent.json'
-
Network: Make sure the remote machine is reachable and the required ports are open
# Test connectivity ping remote-host # Test if the UnitAPI port is open nc -zv remote-host 7890 # Test if the WebSocket port is open nc -zv remote-host 8765
-
Dependencies: Make sure all required dependencies are installed
ssh user@remote-host 'sudo /opt/unitapi/venv/bin/pip list | grep -E "pyaudio|websockets|numpy|sounddevice|soundfile"'
You can customize the Remote Speaker Agent by editing the configuration file:
ssh user@remote-host 'sudo nano /etc/unitapi/speaker_agent.json'
Configuration options:
auto_register_speakers
: Whether to automatically register all detected speakers (default:true
)speakers
: List of manually configured speakers (used whenauto_register_speakers
isfalse
)
You can install the Remote Speaker Agent on multiple machines and control them all from a single client:
# Install on multiple machines
scripts/install_remote_speaker_agent_via_ssh.sh machine1 user1
scripts/install_remote_speaker_agent_via_ssh.sh machine2 user2
# Connect to each machine
python remote_speaker_client.py --host machine1 --list
python remote_speaker_client.py --host machine2 --list
# Play audio on specific speakers on different machines
python remote_speaker_client.py --host machine1 --device speaker_id1 --file audio1.wav
python remote_speaker_client.py --host machine2 --device speaker_id2 --file audio2.wav
The Remote Speaker Agent can be integrated with other UnitAPI devices, such as microphones, cameras, and sensors, to create a complete IoT system:
from unitapi.core.client import UnitAPIClient
# Connect to multiple UnitAPI servers
speaker_client = UnitAPIClient(server_host="speaker-host", server_port=7890)
microphone_client = UnitAPIClient(server_host="microphone-host", server_port=7890)
camera_client = UnitAPIClient(server_host="camera-host", server_port=7890)
# List devices on each server
speakers = await speaker_client.list_devices(device_type="speaker")
microphones = await microphone_client.list_devices(device_type="microphone")
cameras = await camera_client.list_devices(device_type="camera")
# Create a complete IoT system
# ...
[<span style='font-size:20px;'>✍</span>](git@github.com:UnitApi/python/edit/main/examples/README_remote_keyboard_fixed.md)
[<span style='font-size:20px;'>✍</span>](git@github.com:UnitApi/python/edit/main/examples/README_remote_keyboard.md)
[<span style='font-size:20px;'>✍</span>](git@github.com:UnitApi/python/edit/main/examples/remote_keyboard_control.md)
[<span style='font-size:20px;'>✍</span>](git@github.com:UnitApi/python/edit/main/examples/remote_keyboard_server_installation.md)
[<span style='font-size:20px;'>✍</span>](git@github.com:UnitApi/python/edit/main/examples/remote_speaker_agent.md)
# Raspberry Pi Camera Examples for UnitAPI [<span style='font-size:20px;'>✍</span>](git@github.com:UnitApi/python/edit/main/examples/rpi/camera/README.md)
This directory contains examples for controlling a camera on a Raspberry Pi using UnitAPI. These examples demonstrate how to set up a camera server on the Raspberry Pi and control it remotely from a client application.
## Files
- `camera_server.py`: Server that runs on the Raspberry Pi and exposes camera functionality through UnitAPI
- `camera_client.py`: Client that connects to the server and captures images and videos
## Prerequisites
- Raspberry Pi (any model with camera support)
- Raspberry Pi Camera Module (any version) or USB webcam
- Python 3.7 or higher
- UnitAPI installed (`pip install unitapi`)
- For Raspberry Pi Camera Module: `picamera` package
- For USB webcam: `opencv-python` package
## Server Setup
The camera server runs on the Raspberry Pi and exposes camera functionality through UnitAPI. It registers a camera device with the UnitAPI server and handles commands for image capture and video recording.
### Running the Server
```bash
# Run on the Raspberry Pi
python camera_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--resolution
: Camera resolution (default: 640x480)--framerate
: Camera framerate (default: 30)
The camera client connects to the server and controls the camera remotely. It provides methods for capturing images, recording videos, and applying image effects.
# Connect to a local server
python camera_client.py --demo image
# Connect to a remote Raspberry Pi
python camera_client.py --host 192.168.1.100 --port 7890 --demo video
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: image, video, timelapse)--resolution
: Image resolution (e.g., 1920x1080)--output
: Output file path--duration
: Recording duration in seconds (for video demo)--interval
: Interval between captures in seconds (for timelapse demo)
The camera examples support the following operations:
- Capture Image: Take a still image with the camera
- Record Video: Record a video for a specified duration
- Create Timelapse: Capture a series of images at specified intervals
- Apply Image Effects: Apply various effects to the camera output (grayscale, negative, etc.)
- Adjust Camera Settings: Change resolution, framerate, brightness, contrast, etc.
The camera functionality can be integrated with other applications running on the Raspberry Pi. For example:
- Security monitoring systems
- Computer vision applications
- Motion detection
- Timelapse photography
- Video streaming
-
Camera Not Detected: Ensure the camera module is properly connected and enabled in raspi-config:
sudo raspi-config
Then navigate to "Interfacing Options" > "Camera" and enable it.
-
Permission Issues: Some systems may require additional permissions for camera access
# Add user to video group sudo usermod -a -G video $USER
-
Connection Issues: Ensure the server is running and accessible from the client's network
-
Performance Issues: Lower the resolution or framerate if experiencing lag or high CPU usage
- Security Camera: Set up a remote security camera with motion detection
- Timelapse Photography: Create timelapse videos of plants growing, construction projects, etc.
- Computer Vision: Use the camera for object detection, face recognition, or other computer vision tasks
- Remote Monitoring: Monitor a location remotely using the camera
This directory contains examples for controlling GPIO pins on a Raspberry Pi using UnitAPI. These examples demonstrate how to set up a GPIO server on the Raspberry Pi and control it remotely from a client application.
gpio_server.py
: Server that runs on the Raspberry Pi and exposes GPIO functionality through UnitAPIgpio_client.py
: Client that connects to the server and controls GPIO pinsled_control.py
: Advanced LED control examples (blinking, fading, patterns)sensors.py
: Examples for interfacing with various sensors (temperature, distance, motion)
- Raspberry Pi (any model with GPIO pins)
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - RPi.GPIO or gpiozero package installed
- Basic electronic components (LEDs, resistors, sensors, etc.)
The GPIO server runs on the Raspberry Pi and exposes GPIO functionality through UnitAPI. It registers a GPIO device with the UnitAPI server and handles commands for pin mode setting, digital read/write, and PWM control.
# Run on the Raspberry Pi
python gpio_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--pin-mode
: Default pin numbering mode (choices: BCM, BOARD) (default: BCM)
The GPIO client connects to the server and controls the GPIO pins remotely. It provides methods for setting pin modes, reading and writing pin values, and controlling PWM.
# Connect to a local server
python gpio_client.py --led-pin 18 --demo blink
# Connect to a remote Raspberry Pi
python gpio_client.py --host 192.168.1.100 --port 7890 --led-pin 18 --demo blink
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--led-pin
: GPIO pin number for LED (default: 18)--button-pin
: GPIO pin number for button (default: 17)--demo
: Demo to run (choices: blink, fade, button, pwm)
# Connect to a local server
python led_control.py --demo rgb --rgb-mode fade --duration 10
# Connect to a remote Raspberry Pi
python led_control.py --host 192.168.1.100 --port 7890 --demo pattern
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: blink, fade, pattern, rgb)--led-pins
: Comma-separated list of GPIO pins for LEDs (default: 18,23,24)--rgb-pins
: Comma-separated list of GPIO pins for RGB LED (R,G,B) (default: 17,27,22)--rgb-mode
: RGB LED mode (choices: solid, blink, fade, cycle) (default: cycle)--duration
: Duration of the demo in seconds (default: 30)
# Connect to a local server
python sensors.py --demo dht --dht-pin 4 --dht-type DHT22
# Connect to a remote Raspberry Pi
python sensors.py --host 192.168.1.100 --port 7890 --demo ultrasonic
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: dht, ultrasonic, pir, multi)--dht-pin
: GPIO pin for DHT sensor (default: 4)--dht-type
: DHT sensor type (choices: DHT11, DHT22) (default: DHT22)--ultrasonic-trigger
: GPIO pin for ultrasonic sensor trigger (default: 23)--ultrasonic-echo
: GPIO pin for ultrasonic sensor echo (default: 24)--pir-pin
: GPIO pin for PIR motion sensor (default: 17)--duration
: Duration of the demo in seconds (default: 30)
The GPIO examples support the following operations:
- Set Pin Mode: Configure a pin as input or output
- Digital Read: Read the state of an input pin (HIGH/LOW)
- Digital Write: Set the state of an output pin (HIGH/LOW)
- PWM Control: Generate PWM signals for dimming LEDs, controlling motors, etc.
- Sensor Reading: Read values from various sensors connected to GPIO pins
These examples use the BCM (Broadcom) pin numbering scheme, not the physical pin numbers on the Raspberry Pi header. To convert between different numbering schemes, refer to a Raspberry Pi GPIO pinout diagram.
- Be careful when connecting components to GPIO pins. Incorrect wiring can damage your Raspberry Pi.
- Always connect LEDs with appropriate resistors (typically 220-330 ohms) to prevent damage.
- For sensors that require 5V, make sure they have proper level shifting for the GPIO pins which operate at 3.3V.
- Never connect a GPIO pin directly to 5V or ground, as this can damage the pin or the entire Raspberry Pi.
-
Permission Issues: If you encounter permission errors when accessing GPIO pins, try running the server with sudo:
sudo python gpio_server.py
-
Pin Already in Use: If you get an error that a pin is already in use, make sure no other program is using that pin, or choose a different pin.
-
Connection Issues: Ensure the server is running and accessible from the client's network.
-
Wiring Issues: Double-check your wiring connections. Use a multimeter to verify connections if necessary.
- Home Automation: Control lights, fans, and other appliances remotely
- Environmental Monitoring: Monitor temperature, humidity, and other environmental conditions
- Security Systems: Create motion detection systems with PIR sensors
- Interactive Projects: Build interactive projects with buttons, LEDs, and displays
This directory contains examples for controlling a keyboard on a Raspberry Pi using UnitAPI. These examples demonstrate how to set up a keyboard server on the Raspberry Pi and control it remotely from a client application.
keyboard_server.py
: Server that runs on the Raspberry Pi and exposes keyboard functionality through UnitAPIkeyboard_client.py
: Client that connects to the server and controls the keyboard remotely
- Raspberry Pi (any model)
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAutoGUI installed (
pip install pyautogui
)
The keyboard server runs on the Raspberry Pi and exposes keyboard functionality through UnitAPI. It registers a keyboard device with the UnitAPI server and handles commands for key presses, text typing, and keyboard shortcuts.
# Run on the Raspberry Pi
python keyboard_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--device-id
: Custom keyboard device ID (default: keyboard_rpi)--name
: Custom keyboard device name (default: Raspberry Pi Keyboard)
The keyboard client connects to the server and controls the keyboard remotely. It provides methods for typing text, pressing keys, and using keyboard shortcuts.
# Connect to a local server
python keyboard_client.py --demo typing
# Connect to a remote Raspberry Pi
python keyboard_client.py --host 192.168.1.100 --port 7890 --demo all
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: typing, hotkey, sequence, all)--text
: Text to type (for custom commands)--key
: Key to press (for custom commands)--hotkey
: Hotkey to press (comma-separated keys, e.g., ctrl,s)
The client provides several demo modes:
- Typing Demo (
--demo typing
): Demonstrates typing text and pressing Enter - Hotkey Demo (
--demo hotkey
): Demonstrates using keyboard shortcuts like Ctrl+A - Key Sequence Demo (
--demo sequence
): Demonstrates using arrow keys and modifier keys - All Demos (
--demo all
): Runs all demos in sequence
You can also use the client to execute specific keyboard commands:
# Type specific text
python keyboard_client.py --text "Hello, world!"
# Press a specific key
python keyboard_client.py --key enter
# Press a specific hotkey combination
python keyboard_client.py --hotkey ctrl,s
The keyboard examples support the following operations:
- Key Down: Press and hold a key
- Key Up: Release a key
- Press Key: Press and release a key
- Type Text: Type a sequence of characters
- Press Hotkey: Press a combination of keys simultaneously
- Release All Keys: Release all currently pressed keys
The keyboard functionality can be integrated with other applications running on the Raspberry Pi. For example:
- Control text editors or command-line interfaces
- Automate form filling in web browsers
- Control games or other applications
- Implement custom keyboard shortcuts for specific tasks
Remote keyboard control provides powerful capabilities but also introduces security risks. Consider the following:
- Run the server on a secure, private network
- Use UnitAPI's authentication and encryption features
- Be cautious about allowing remote keyboard control in sensitive environments
- Consider implementing additional access controls based on your specific requirements
- Connection Issues: Ensure the server is running and accessible from the client's network
- Permission Issues: Some systems may require additional permissions for keyboard control
- Key Mapping Issues: Different keyboard layouts may require adjustments to key mappings
- Stuck Keys: If keys appear to be stuck, use the
release_all_keys
command to reset the keyboard state
- Remote Control: Control applications on a headless Raspberry Pi
- Automation: Automate repetitive keyboard tasks
- Kiosk Systems: Implement controlled keyboard input for kiosk applications
- Accessibility: Create custom keyboard interfaces for accessibility purposes
This document provides information about installing and configuring the UnitAPI Remote Keyboard Server on a Raspberry Pi.
The Remote Keyboard Server allows you to control a Raspberry Pi's keyboard remotely using the UnitAPI framework. This enables you to send keystrokes to the Raspberry Pi from another computer, which can be useful for remote control, automation, and testing scenarios.
There are two installation scripts available:
- Standard Installation Script:
scripts/install_remote_keyboard_server.sh
- Fixed Installation Script:
scripts/install_remote_keyboard_server_fixed.sh
(Recommended)
The fixed installation script includes several improvements to handle common installation issues.
The install_remote_keyboard_server_fixed.sh
script includes the following improvements:
-
Improved SSH Authentication:
- Explicitly disables pubkey authentication when using password authentication to prevent "too many authentication failures" errors
- Adds retry mechanism for SSH connections with configurable number of attempts
- Provides better error messages for authentication failures
-
Repository Handling:
- Detects outdated Raspberry Pi OS versions (like "stretch")
- Updates repository sources to use archive repositories for outdated OS versions
- Prevents 404 errors when accessing outdated repositories
-
SSL Certificate Verification:
- Disables SSL certificate verification for pip installations using
--trusted-host
flags - Resolves SSL certificate verification failures when installing Python packages
- Adds trusted hosts for both PyPI and piwheels repositories
- Disables SSL certificate verification for pip installations using
-
Improved File Transfer:
- Adds retry mechanism for SCP file transfers
- Verifies successful file transfers before proceeding
- Creates a local service file and transfers it directly to avoid path issues
-
Error Handling and Recovery:
- Adds retry mechanisms for package installation and unitapi installation
- Continues installation even if some steps fail, with appropriate warnings
- Provides more detailed error messages and status updates
./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --password raspberry
./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --identity ~/.ssh/id_rsa
# Start the service
./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --password raspberry --service-command start
# Stop the service
./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --password raspberry --service-command stop
# Restart the service
./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --password raspberry --service-command restart
# Check service status
./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --password raspberry --service-command status
After installing the Remote Keyboard Server on your Raspberry Pi, you need to configure the client to connect to it.
- Update your
.env
file with the following:
RPI_HOST=192.168.1.100 # Replace with your Raspberry Pi's IP address
RPI_USER=pi # Replace with your Raspberry Pi username
RPI_PASSWORD=raspberry # Replace with your Raspberry Pi password
- Run the client:
python examples/remote_keyboard_control_fixed.py
Note: We recommend using the fixed version of the client script (
remote_keyboard_control_fixed.py
) instead of the original version (remote_keyboard_control.py
). The fixed version includes better error handling, connection checking, and troubleshooting guidance.
The remote keyboard control client supports several command-line options:
python examples/remote_keyboard_control_fixed.py --help
Common options include:
--check-connection
: Test the connection to the remote server--list
: List available keyboards on the remote device--device-id DEVICE_ID
: Specify a keyboard device ID to control--text TEXT
: Type the specified text on the remote keyboard--key KEY
: Press a specific key on the remote keyboard--hotkey KEYS
: Press a hotkey combination (comma-separated keys, e.g., ctrl,s)
If you're experiencing SSH connection issues:
-
Verify that the Raspberry Pi is reachable on the network:
ping <raspberry_pi_ip>
-
Check that SSH is enabled on the Raspberry Pi:
ssh <username>@<raspberry_pi_ip>
-
If using password authentication, ensure the password is correct.
-
If using key-based authentication, ensure the key file exists and has the correct permissions:
chmod 600 ~/.ssh/id_rsa
If package installation fails:
-
Check the Raspberry Pi's internet connection.
-
Try updating the package lists manually:
sudo apt-get update
-
If using an outdated Raspberry Pi OS version, consider upgrading to a newer version.
If the service fails to start:
-
Check the service status:
sudo systemctl status unitapi-keyboard.service
-
Check the service logs:
journalctl -u unitapi-keyboard.service
-
Verify that the Python virtual environment was created correctly:
ls -la /home/pi/unitapi/venv/bin/python
If you prefer using Python instead of Bash for installation, you can use the scripts/install_remote_keyboard_server.py
script:
python scripts/install_remote_keyboard_server.py --host 192.168.1.100 --password raspberry
This Python script provides similar functionality to the Bash script but may be more suitable for environments where Python is preferred over Bash.
This directory contains examples for controlling a microphone on a Raspberry Pi using UnitAPI. These examples demonstrate how to set up a microphone server on the Raspberry Pi and control it remotely from a client application.
microphone_server.py
: Server that runs on the Raspberry Pi and exposes microphone functionality through UnitAPImicrophone_client.py
: Client that connects to the server and records audio and monitors levels
- Raspberry Pi (any model)
- USB microphone or audio HAT
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAudio installed (
pip install pyaudio
) - For audio format conversion:
ffmpeg
installed
The microphone server runs on the Raspberry Pi and exposes microphone functionality through UnitAPI. It registers a microphone device with the UnitAPI server and handles commands for audio recording and level monitoring.
# Run on the Raspberry Pi
python microphone_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging
The microphone client connects to the server and controls the microphone remotely. It provides methods for recording audio and monitoring audio levels.
# Connect to a local server
python microphone_client.py --demo record --duration 10
# Connect to a remote Raspberry Pi
python microphone_client.py --host 192.168.1.100 --port 7890 --demo monitor
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: record, monitor, vad)--duration
: Recording/monitoring duration in seconds (default: 5.0)--sample-rate
: Audio sample rate in Hz (default: 44100)--channels
: Number of audio channels (default: 1)--format
: Audio format (choices: wav, mp3) (default: wav)--output
: Output file path--threshold
: Voice activity detection threshold (default: 0.1)
The client provides several demo modes:
- Record Demo (
--demo record
): Records audio for a specified duration and saves it to a file - Monitor Demo (
--demo monitor
): Monitors audio levels in real-time and displays a level meter - Voice Activity Detection Demo (
--demo vad
): Detects voice activity based on audio levels
The microphone examples support the following operations:
- Start Recording: Begin recording audio with specified parameters
- Stop Recording: Stop recording and save the audio file
- Get Audio Level: Get the current audio input level
- Voice Activity Detection: Detect when someone is speaking
The microphone examples support the following audio formats:
- WAV: Uncompressed audio format (default)
- MP3: Compressed audio format (requires ffmpeg)
-
Microphone Not Detected: Ensure the microphone is properly connected and recognized by the system:
# List audio input devices arecord -l
-
Permission Issues: Some systems may require additional permissions for audio access:
# Add user to audio group sudo usermod -a -G audio $USER
-
PyAudio Installation Issues: If you have trouble installing PyAudio, try:
# Install dependencies sudo apt-get install portaudio19-dev python3-pyaudio # Then install PyAudio pip install pyaudio
-
Audio Quality Issues: If you experience poor audio quality, try adjusting the sample rate or using a different microphone.
-
Connection Issues: Ensure the server is running and accessible from the client's network.
- Voice Assistant: Create a voice-controlled assistant using the microphone for input
- Audio Monitoring: Monitor sound levels in a room or environment
- Voice Recording: Record voice memos or audio notes remotely
- Sound Detection: Create a system that responds to specific sounds or noise levels
- Voice Activity Detection: Trigger actions when voice activity is detected
This directory contains examples for controlling a mouse on a Raspberry Pi using UnitAPI. These examples demonstrate how to set up a mouse server on the Raspberry Pi and control it remotely from a client application.
mouse_server.py
: Server that runs on the Raspberry Pi and exposes mouse functionality through UnitAPImouse_client.py
: Client that connects to the server and controls the mouse remotely
- Raspberry Pi (any model)
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAutoGUI installed (
pip install pyautogui
)
The mouse server runs on the Raspberry Pi and exposes mouse functionality through UnitAPI. It registers a mouse device with the UnitAPI server and handles commands for mouse movement, clicks, scrolling, and drag operations.
# Run on the Raspberry Pi
python mouse_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--device-id
: Custom mouse device ID (default: mouse_rpi)--name
: Custom mouse device name (default: Raspberry Pi Mouse)
The mouse client connects to the server and controls the mouse remotely. It provides methods for moving the mouse, clicking, scrolling, and performing drag operations.
# Connect to a local server
python mouse_client.py --demo movement
# Connect to a remote Raspberry Pi
python mouse_client.py --host 192.168.1.100 --port 7890 --demo all
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: movement, click, scroll, drag, all)--x
: X coordinate for move_to command--y
: Y coordinate for move_to command--dx
: X delta for move_relative command--dy
: Y delta for move_relative command--button
: Mouse button for click commands (choices: left, right, middle)--scroll-amount
: Scroll amount (positive for up, negative for down)
The client provides several demo modes:
- Movement Demo (
--demo movement
): Demonstrates moving the mouse in patterns (square, circle) - Click Demo (
--demo click
): Demonstrates different types of mouse clicks (left, right, double) - Scroll Demo (
--demo scroll
): Demonstrates scrolling up and down - Drag Demo (
--demo drag
): Demonstrates dragging operations - All Demos (
--demo all
): Runs all demos in sequence
You can also use the client to execute specific mouse commands:
# Move to specific coordinates
python mouse_client.py --x 500 --y 500
# Move by a relative amount
python mouse_client.py --dx 100 --dy -50
# Click a specific button
python mouse_client.py --button right
# Scroll up or down
python mouse_client.py --scroll-amount 10
The mouse examples support the following operations:
- Move To: Move mouse cursor to absolute position
- Move Relative: Move mouse cursor by a relative amount
- Click: Perform a mouse click (left, right, or middle button)
- Double Click: Perform a mouse double-click
- Button Down: Press and hold a mouse button
- Button Up: Release a mouse button
- Scroll: Scroll the mouse wheel
- Drag: Perform a drag operation from current position to target position
The mouse functionality can be integrated with other applications running on the Raspberry Pi. For example:
- Control graphical user interfaces
- Automate testing of GUI applications
- Create custom input devices for specific applications
- Implement remote control for Raspberry Pi-based kiosks or displays
Remote mouse control provides powerful capabilities but also introduces security risks. Consider the following:
- Run the server on a secure, private network
- Use UnitAPI's authentication and encryption features
- Be cautious about allowing remote mouse control in sensitive environments
- Consider implementing additional access controls based on your specific requirements
- Connection Issues: Ensure the server is running and accessible from the client's network
- Permission Issues: Some systems may require additional permissions for mouse control
- Coordinate Issues: Screen coordinates are relative to the Raspberry Pi's display resolution
- Performance Issues: Reduce the frequency of mouse operations if experiencing lag
- Remote Control: Control applications on a headless Raspberry Pi
- Automation: Automate repetitive mouse tasks
- Kiosk Systems: Implement controlled mouse input for kiosk applications
- Accessibility: Create custom mouse interfaces for accessibility purposes
This directory contains examples specifically designed for using UnitAPI with Raspberry Pi hardware. These examples demonstrate how to interact with various Raspberry Pi hardware components like GPIO pins, camera modules, microphones, speakers, and sensors.
The examples are organized by device type:
-
gpio/: GPIO and sensor examples
gpio_server.py
: Server for GPIO functionalitygpio_client.py
: Client for controlling GPIO pinsled_control.py
: Advanced LED control examplessensors.py
: Examples for various sensors (temperature, distance, etc.)
-
camera/: Camera module examples
camera_server.py
: Server for camera functionalitycamera_client.py
: Client for capturing images and videos
-
mic/: Microphone examples
microphone_server.py
: Server for microphone functionalitymicrophone_client.py
: Client for recording audio and monitoring levels
-
speaker/: Speaker examples
speaker_server.py
: Server for speaker functionalityspeaker_client.py
: Client for audio playback and volume control
-
respeaker/: ReSpeaker microphone array examples
respeaker_server.py
: Server for ReSpeaker functionalityrespeaker_client.py
: Client for audio recording, direction of arrival, and LED control
- Raspberry Pi (any model with GPIO pins)
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - Required Python packages for specific examples:
- For camera examples:
picamera
oropencv-python
- For audio examples:
pyaudio
- For sensor examples:
Adafruit_DHT
(for DHT11/DHT22 sensors) - For ReSpeaker examples:
numpy
- For camera examples:
These examples follow a client-server architecture:
- Server: Runs on the Raspberry Pi and exposes hardware functionality through UnitAPI
- Client: Connects to the server and controls the hardware remotely
Before running any client examples, you need to start the corresponding server on your Raspberry Pi:
# Start the GPIO server
python gpio/gpio_server.py --host 0.0.0.0 --port 7890
# Start the Camera server
python camera/camera_server.py --host 0.0.0.0 --port 7890
# Start the Microphone server
python mic/microphone_server.py --host 0.0.0.0 --port 7890
# Start the Speaker server
python speaker/speaker_server.py --host 0.0.0.0 --port 7890
# Start the ReSpeaker server
python respeaker/respeaker_server.py --host 0.0.0.0 --port 7890
The servers will expose the hardware functionality through UnitAPI, making it available for client applications to connect.
Exposes GPIO functionality through UnitAPI:
- Registers a GPIO device with the UnitAPI server
- Handles commands for pin mode setting, digital read/write, and PWM control
- Provides a clean shutdown mechanism
Usage:
# Run on the Raspberry Pi
python gpio/gpio_server.py --host 0.0.0.0 --port 7890
Demonstrates basic GPIO pin control on Raspberry Pi, including:
- Setting pin modes (input/output)
- Digital read/write operations
- PWM (Pulse Width Modulation) control
- Blinking LEDs
- Fading LEDs using PWM
Usage:
# Connect to a local server
python gpio/gpio_client.py --led-pin 18 --demo blink
# Connect to a remote Raspberry Pi
python gpio/gpio_client.py --host 192.168.1.100 --port 7890 --led-pin 18 --demo blink
Advanced LED control examples for Raspberry Pi:
- Blinking individual LEDs
- Fading LEDs with PWM
- Creating LED patterns with multiple LEDs
- Controlling RGB LEDs
Usage:
# Connect to a local GPIO server
python gpio/led_control.py --demo rgb --rgb-mode fade --duration 10
Demonstrates interfacing with various sensors connected to Raspberry Pi GPIO:
- DHT11/DHT22 temperature and humidity sensors
- HC-SR04 ultrasonic distance sensors
- PIR motion sensors
- Multi-sensor monitoring
Usage:
# Connect to a local GPIO server
python gpio/sensors.py --demo dht --dht-pin 4 --dht-type DHT22
Exposes Raspberry Pi Camera Module functionality through UnitAPI:
- Registers a camera device with the UnitAPI server
- Handles commands for image capture and video recording
- Supports various image effects and resolutions
- Falls back to a virtual camera if no physical camera is detected
Usage:
# Run on the Raspberry Pi
python camera/camera_server.py --host 0.0.0.0 --port 7890
Demonstrates using the Raspberry Pi Camera Module with UnitAPI:
- Capturing still images
- Recording video
- Creating timelapse sequences
- Applying image effects
Usage:
# Connect to a local server
python camera/camera_client.py --demo image --resolution 1920x1080
Exposes microphone functionality through UnitAPI:
- Registers a microphone device with the UnitAPI server
- Handles commands for audio recording and level monitoring
- Supports various audio formats and sample rates
Usage:
# Run on the Raspberry Pi
python mic/microphone_server.py --host 0.0.0.0 --port 7890
Demonstrates using the Raspberry Pi microphone with UnitAPI:
- Recording audio to WAV or MP3 files
- Monitoring audio levels
- Voice activity detection
Usage:
# Connect to a local server
python mic/microphone_client.py --demo record --duration 10
Exposes speaker functionality through UnitAPI:
- Registers a speaker device with the UnitAPI server
- Handles commands for audio playback and volume control
- Supports various audio formats
Usage:
# Run on the Raspberry Pi
python speaker/speaker_server.py --host 0.0.0.0 --port 7890
Demonstrates using the Raspberry Pi speaker with UnitAPI:
- Playing audio files
- Generating and playing tones
- Controlling system volume
Usage:
# Connect to a local server
python speaker/speaker_client.py --demo file --audio-file sample.wav
Exposes ReSpeaker microphone array functionality through UnitAPI:
- Registers a ReSpeaker device with the UnitAPI server
- Handles commands for audio recording, direction of arrival, and LED control
- Supports the ReSpeaker 4-Mic Array for Raspberry Pi
Usage:
# Run on the Raspberry Pi
python respeaker/respeaker_server.py --host 0.0.0.0 --port 7890
Demonstrates using the ReSpeaker microphone array with UnitAPI:
- Recording audio with beamforming
- Getting direction of arrival (DOA)
- Controlling the LED ring
- Voice localization demo
Usage:
# Connect to a local server
python respeaker/respeaker_client.py --demo voice --duration 30
- Raspberry Pi with GPIO pins
- LEDs, resistors (220-330 ohm)
- Push buttons
- Sensors (DHT11/DHT22, HC-SR04, PIR) as needed
- Raspberry Pi Camera Module (any version)
- Or USB webcam compatible with Linux
- USB microphone
- Or Raspberry Pi compatible audio HAT
- USB speakers
- Or Raspberry Pi compatible audio HAT
- Or HDMI audio output
- ReSpeaker 4-Mic Array for Raspberry Pi
- Or ReSpeaker 2-Mic HAT
The client and server communicate using the UnitAPI protocol:
- The server registers devices and command handlers
- The client connects to the server and discovers available devices
- The client sends commands to control the devices
- The server executes the commands and returns the results
This architecture allows for:
- Remote control of Raspberry Pi hardware
- Multiple clients connecting to the same server
- Separation of hardware control logic from application logic
These examples use the BCM (Broadcom) pin numbering scheme, not the physical pin numbers on the Raspberry Pi header. To convert between different numbering schemes, refer to a Raspberry Pi GPIO pinout diagram.
-
Permission Issues: If you encounter permission errors when accessing hardware, try running the server with sudo:
sudo python gpio/gpio_server.py
-
Camera Not Detected: Ensure the camera module is properly connected and enabled in raspi-config:
sudo raspi-config
Then navigate to "Interfacing Options" > "Camera" and enable it.
-
Audio Issues: If you have issues with audio input/output:
# List audio devices arecord -l # Input devices aplay -l # Output devices # Test microphone recording arecord -d 5 -f cd test.wav # Test speaker playback aplay test.wav
-
ReSpeaker Issues: For ReSpeaker setup problems:
# Check if ReSpeaker is detected lsusb # Install ReSpeaker drivers if needed git clone https://github.com/respeaker/seeed-voicecard cd seeed-voicecard sudo ./install.sh sudo reboot
-
Server Connection Issues: If the client cannot connect to the server, check:
- The server is running and listening on the correct interface (0.0.0.0 for all interfaces)
- The port is not blocked by a firewall
- The host and port in the client match the server
- Network connectivity between client and server
- Be careful when connecting components to GPIO pins. Incorrect wiring can damage your Raspberry Pi.
- Always connect LEDs with appropriate resistors (typically 220-330 ohms) to prevent damage.
- For sensors that require 5V, make sure they have proper level shifting for the GPIO pins which operate at 3.3V.
This directory contains examples for controlling a ReSpeaker microphone array on a Raspberry Pi using UnitAPI. These examples demonstrate how to set up a ReSpeaker server on the Raspberry Pi and control it remotely from a client application.
respeaker_server.py
: Server that runs on the Raspberry Pi and exposes ReSpeaker functionality through UnitAPIrespeaker_client.py
: Client that connects to the server and controls the ReSpeaker microphone array
- Raspberry Pi (any model)
- ReSpeaker 4-Mic Array for Raspberry Pi or ReSpeaker 2-Mic HAT
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - ReSpeaker drivers and libraries installed
- NumPy installed (
pip install numpy
)
Before using these examples, you need to install the ReSpeaker drivers and libraries:
# Clone the ReSpeaker drivers repository
git clone https://github.com/respeaker/seeed-voicecard
cd seeed-voicecard
# Install the drivers
sudo ./install.sh
sudo reboot
# Install the ReSpeaker Python library
pip install respeaker
The ReSpeaker server runs on the Raspberry Pi and exposes ReSpeaker functionality through UnitAPI. It registers a ReSpeaker device with the UnitAPI server and handles commands for audio recording, direction of arrival (DOA), and LED control.
# Run on the Raspberry Pi
python respeaker_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--model
: ReSpeaker model (choices: 4mic, 2mic) (default: 4mic)
The ReSpeaker client connects to the server and controls the ReSpeaker microphone array remotely. It provides methods for recording audio with beamforming, getting direction of arrival (DOA), and controlling the LED ring.
# Connect to a local server
python respeaker_client.py --demo voice --duration 30
# Connect to a remote Raspberry Pi
python respeaker_client.py --host 192.168.1.100 --port 7890 --demo doa
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: voice, doa, led, all)--duration
: Duration of the demo in seconds (default: 30)--output
: Output file path for audio recording--sample-rate
: Audio sample rate in Hz (default: 16000)--channels
: Number of audio channels (default: 1)--format
: Audio format (choices: wav, mp3) (default: wav)
The client provides several demo modes:
- Voice Demo (
--demo voice
): Records audio with beamforming and saves it to a file - Direction of Arrival Demo (
--demo doa
): Continuously displays the direction of sound sources - LED Demo (
--demo led
): Demonstrates various LED patterns on the ReSpeaker's LED ring - All Demos (
--demo all
): Runs all demos in sequence
The ReSpeaker examples support the following operations:
- Audio Recording with Beamforming: Record audio with enhanced directional sensitivity
- Direction of Arrival (DOA): Determine the direction of sound sources
- LED Control: Control the LED ring on the ReSpeaker 4-Mic Array
- Voice Localization: Visualize the direction of voice sources
These examples support the following ReSpeaker models:
- ReSpeaker 4-Mic Array for Raspberry Pi: Features 4 microphones and an LED ring
- ReSpeaker 2-Mic HAT: Features 2 microphones and 3 LEDs
-
ReSpeaker Not Detected: Ensure the ReSpeaker is properly connected and the drivers are installed:
# Check if ReSpeaker is detected arecord -l
-
Driver Installation Issues: If you have trouble installing the drivers, try:
# Update your system first sudo apt-get update sudo apt-get upgrade # Then reinstall the drivers cd seeed-voicecard sudo ./install.sh sudo reboot
-
LED Control Issues: If the LEDs don't work, check if the SPI interface is enabled:
# Enable SPI interface sudo raspi-config # Navigate to "Interfacing Options" > "SPI" and enable it
-
Audio Quality Issues: If you experience poor audio quality, try adjusting the microphone gain or using a different beamforming algorithm.
-
Connection Issues: Ensure the server is running and accessible from the client's network.
- Voice Assistant: Create a voice-controlled assistant with directional awareness
- Sound Localization: Determine the direction of sound sources in a room
- Interactive LED Feedback: Provide visual feedback through the LED ring based on sound direction
- Multi-Room Audio: Create a distributed audio recording system with multiple ReSpeakers
- Conference Room System: Build a smart conference room system with directional audio recording
This directory contains examples for controlling a speaker on a Raspberry Pi using UnitAPI. These examples demonstrate how to set up a speaker server on the Raspberry Pi and control it remotely from a client application.
speaker_server.py
: Server that runs on the Raspberry Pi and exposes speaker functionality through UnitAPIspeaker_client.py
: Client that connects to the server and controls audio playback and volume
- Raspberry Pi (any model)
- Speaker connected via 3.5mm audio jack, HDMI, USB, or audio HAT
- Python 3.7 or higher
- UnitAPI installed (
pip install unitapi
) - PyAudio installed (
pip install pyaudio
) - For audio format support:
ffmpeg
installed
The speaker server runs on the Raspberry Pi and exposes speaker functionality through UnitAPI. It registers a speaker device with the UnitAPI server and handles commands for audio playback and volume control.
# Run on the Raspberry Pi
python speaker_server.py --host 0.0.0.0 --port 7890
Options:
--host
: Server host address (default: 0.0.0.0)--port
: Server port (default: 7890)--debug
: Enable debug logging--device-index
: Audio output device index (default: system default)
The speaker client connects to the server and controls the speaker remotely. It provides methods for playing audio files, generating and playing tones, and controlling system volume.
# Connect to a local server
python speaker_client.py --demo file --audio-file sample.wav
# Connect to a remote Raspberry Pi
python speaker_client.py --host 192.168.1.100 --port 7890 --demo tone
Options:
--host
: UnitAPI server host (default: localhost)--port
: UnitAPI server port (default: 7890)--debug
: Enable debug logging--demo
: Demo to run (choices: file, tone, volume, all)--audio-file
: Audio file to play (for file demo)--frequency
: Tone frequency in Hz (default: 440)--duration
: Tone or volume change duration in seconds (default: 3.0)--volume
: Volume level (0.0-1.0) (default: 0.5)
The client provides several demo modes:
- File Demo (
--demo file
): Plays an audio file - Tone Demo (
--demo tone
): Generates and plays a tone with specified frequency - Volume Demo (
--demo volume
): Demonstrates volume control - All Demos (
--demo all
): Runs all demos in sequence
The speaker examples support the following operations:
- Play Audio File: Play audio files in various formats (WAV, MP3, etc.)
- Play Tone: Generate and play a tone with specified frequency and duration
- Set Volume: Control the system volume
- Stop Playback: Stop the current audio playback
- Get Playback Status: Get the current playback status
The speaker examples support the following audio formats:
- WAV: Uncompressed audio format
- MP3: Compressed audio format
- OGG: Compressed audio format
- FLAC: Lossless compressed audio format
- Other formats supported by ffmpeg
-
Speaker Not Detected: Ensure the speaker is properly connected and recognized by the system:
# List audio output devices aplay -l
-
No Sound: Check if the volume is muted or too low:
# Check and adjust volume amixer sset 'Master' 80%
-
Permission Issues: Some systems may require additional permissions for audio access:
# Add user to audio group sudo usermod -a -G audio $USER
-
PyAudio Installation Issues: If you have trouble installing PyAudio, try:
# Install dependencies sudo apt-get install portaudio19-dev python3-pyaudio # Then install PyAudio pip install pyaudio
-
Audio Quality Issues: If you experience poor audio quality, try using a different audio output device or format.
-
Connection Issues: Ensure the server is running and accessible from the client's network.
- Remote Audio Player: Control audio playback on a Raspberry Pi from another device
- Notification System: Play alert sounds or notifications remotely
- Multi-Room Audio: Create a distributed audio system with multiple Raspberry Pis
- Text-to-Speech Output: Combine with a text-to-speech service to create voice announcements
- Interactive Projects: Add audio feedback to interactive projects
✍
This example demonstrates how to set up a virtual speaker server on one machine (PC1) and a client on another machine (PC2) using Docker Compose. The client will install the UnitAPI speaker agent on the server using SSH and then connect to it to control the virtual speakers.
This Docker Compose setup creates two containers:
- speaker-server: A container that runs virtual speakers and exposes them through the UnitAPI protocol.
- speaker-client: A container that connects to the speaker server, installs the UnitAPI speaker agent using SSH, and provides a client interface to control the speakers.
This setup simulates a real-world scenario where you have a remote PC with speakers that you want to control from another PC.
- Docker and Docker Compose installed on your machine
- Basic knowledge of Docker and Docker Compose
- Understanding of the UnitAPI speaker agent
docker/
├── docker-compose.yml # Docker Compose configuration
├── README.md # This file
├── speaker-server/ # Server container files
│ ├── Dockerfile # Server container definition
│ ├── entrypoint.sh # Server startup script
│ ├── virtual_speaker.py # Virtual speaker implementation
│ └── data/ # Shared volume for server data
└── speaker-client/ # Client container files
├── Dockerfile # Client container definition
├── entrypoint.sh # Client startup script
├── client.py # Speaker client implementation
└── data/ # Shared volume for client data
- The
speaker-server
container creates virtual speakers and exposes them through the UnitAPI protocol. - The
speaker-client
container connects to the server via SSH and installs the UnitAPI speaker agent. - The client then connects to the server's UnitAPI interface to control the virtual speakers.
This simulates the process of installing the UnitAPI speaker agent on a remote PC and controlling its speakers.
# Navigate to the docker directory
cd examples/docker
# Start the containers
docker-compose up -d
# View the logs
docker-compose logs -f
# Access the client container shell
docker exec -it unitapi-speaker-client bash
# Inside the container, you can use the client script
python /opt/unitapi/client.py --host 172.28.1.2 --list
python /opt/unitapi/client.py --host 172.28.1.2 --test
# Access the server container shell
docker exec -it unitapi-speaker-server bash
# Inside the container, you can check the speaker agent status
unitapi-speaker --status
unitapi-speaker --list
# Stop the containers
docker-compose down
You can customize the setup by modifying the following files:
docker-compose.yml
: Change the network configuration, port mappings, etc.speaker-server/virtual_speaker.py
: Modify the virtual speaker implementation.speaker-client/client.py
: Customize the client behavior.
The Docker Compose setup supports the following environment variables:
VIRTUAL_SPEAKERS
: Number of virtual speakers to create on the server (default: 2)SERVER_HOST
: Hostname or IP address of the server (default: 172.28.1.2)SERVER_PORT
: Port number of the UnitAPI server (default: 7890)
You can set these variables in the docker-compose.yml
file or pass them when starting the containers:
VIRTUAL_SPEAKERS=4 docker-compose up -d
Once the containers are running, you can test the setup by:
-
Listing the available speakers:
docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --list
-
Testing all speakers:
docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --test
-
Testing a specific speaker:
docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --device virtual_speaker_1
-
Monitoring the speakers:
docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --monitor --interval 30
If you encounter issues with the setup, check the following:
-
Make sure the containers are running:
docker-compose ps
-
Check the container logs:
docker-compose logs -f
-
Verify the network connectivity between the containers:
docker exec -it unitapi-speaker-client ping 172.28.1.2
-
Check if the SSH server is running on the server container:
docker exec -it unitapi-speaker-server service ssh status
-
Verify the UnitAPI server is running on the server container:
docker exec -it unitapi-speaker-server ps aux | grep unitapi
You can extend this example to include more features:
- Add more virtual speakers by changing the
VIRTUAL_SPEAKERS
environment variable. - Implement a web interface for controlling the speakers.
- Add support for playing audio files from the client to the server.
- Integrate with other UnitAPI devices like microphones or cameras.
This Docker example demonstrates how to use the UnitAPI speaker agent to control speakers on a remote machine. It shows the process of installing the agent via SSH and then using it to control the speakers. This can be used as a starting point for building more complex applications that involve remote audio control.
tree -L 4 src
src
├── unitapi
│ ├── core
│ │ ├── client_fixed.py
│ │ ├── client.py
│ │ ├── __init__.py
│ │ └── server.py
│ ├── devices
│ │ ├── base.py
│ │ ├── camera.py
│ │ ├── gamepad.py
│ │ ├── gpio.py
│ │ ├── __init__.py
│ │ ├── keyboard.py
│ │ ├── microphone.py
│ │ ├── mouse.py
│ │ ├── remote_speaker_device.py
│ │ ├── remote_speaker_service.py
│ │ └── touchscreen.py
│ ├── __init__.py
│ ├── __main__.py
│ ├── main.py
│ ├── protocols
│ │ ├── base.py
│ │ ├── __init__.py
│ │ ├── mqtt.py
│ │ └── websocket.py
│ ├── security
│ │ ├── access_control.py
│ │ ├── authentication.py
│ │ ├── encryption.py
│ │ ├── __init__.py
│ ├── _version.py
│ └── _version.py.bak
└── __init__.py
tree -L 4 examples
examples
├── camera_capture.py
├── camera_frame_capture.py
├── device_discovery.py
├── docker
│ ├── docker-compose.yml
│ ├── README.md
│ ├── speaker-client
│ │ ├── client.py
│ │ ├── data
│ │ ├── Dockerfile
│ │ └── entrypoint.sh
│ └── speaker-server
│ ├── data
│ ├── Dockerfile
│ ├── entrypoint.sh
│ └── virtual_speaker.py
├── examples.md
├── input_devices.py
├── keyboard_text_input.py
├── microphone_audio_input.py
├── microphone_recording.py
├── mouse_movement.py
├── mouse_movement_pyautogui.py
├── pc
│ ├── camera
│ │ ├── camera_client.py
│ │ ├── camera_frame_client.py
│ │ ├── camera_server.py
│ │ ├── README.md
│ │ ├── remote_camera_capture.py
│ │ ├── remote_camera_client.py
│ │ ├── remote_camera_frame_capture.py
│ │ ├── remote_camera_frame_client.py
│ │ └── screenshot_client.py
│ ├── keyboard
│ │ ├── keyboard_client.py
│ │ ├── keyboard_server.py
│ │ ├── README.md
│ │ ├── README_remote_keyboard_fixed.md
│ │ ├── README_remote_keyboard.md
│ │ ├── remote_keyboard_client.py
│ │ ├── remote_keyboard_control_fixed.py
│ │ └── remote_keyboard_control.py
│ ├── microphone
│ │ ├── microphone_input_client.py
│ │ ├── microphone_recording_client.py
│ │ ├── microphone_server.py
│ │ └── README.md
│ ├── misc
│ │ ├── device_discovery.py
│ │ ├── input_devices.py
│ │ ├── README.md
│ │ ├── remote_control.py
│ │ └── ssh_connector.py
│ ├── mouse
│ │ ├── mouse_client.py
│ │ ├── mouse_pyautogui_client.py
│ │ ├── mouse_server.py
│ │ └── README.md
│ ├── README.md
│ └── speaker
│ ├── README.md
│ ├── remote_speaker_agent.md
│ ├── speaker_audio_playback_fixed.py
│ ├── speaker_audio_playback.py
│ ├── speaker_client.py
│ ├── speaker_playback_fixed.py
│ ├── speaker_playback.py
│ └── speaker_server.py
├── rpi
│ ├── camera
│ │ ├── camera_client.py
│ │ ├── camera_server.py
│ │ └── README.md
│ ├── gpio
│ │ ├── gpio_client.py
│ │ ├── gpio_server.py
│ │ ├── led_control.py
│ │ ├── README.md
│ │ └── sensors.py
│ ├── keyboard
│ │ ├── keyboard_client.py
│ │ ├── keyboard_server.py
│ │ ├── README.md
│ │ ├── remote_keyboard_server_installation.md
│ │ └── remote_keyboard_server.py
│ ├── mic
│ │ ├── microphone_client.py
│ │ ├── microphone_server.py
│ │ └── README.md
│ ├── mouse
│ │ ├── mouse_client.py
│ │ ├── mouse_server.py
│ │ └── README.md
│ ├── README.md
│ ├── respeaker
│ │ ├── README.md
│ │ ├── respeaker_client.py
│ │ └── respeaker_server.py
│ └── speaker
│ ├── README.md
│ ├── speaker_client.py
│ └── speaker_server.py
├── speaker_audio_playback_fixed.py
├── speaker_audio_playback.py
├── speaker_client.py
├── speaker_playback_fixed.py
├── speaker_playback_fix.md
├── speaker_playback.py
├── speaker_server.py
├── ssh_connector_example.py
├── stream_processing.py
└── take_screenshot.py
✍
<script type="module"> import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; //import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10.8.0/dist/mermaid.min.js'; mermaid.initialize({ startOnReady:true, theme: 'forest', flowchart:{ useMaxWidth:false, htmlLabels:true } }); mermaid.init(undefined, '.language-mermaid'); </script>- Modular Documentation made possible by the FlatEdit project.