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.
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)
We welcome contributions! Please read our Contribution Guidelines for details on how to get started.
UnitAPI is open-source software licensed under the MIT License.
Current Version: 0.1.5
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:
Camera devices provide interfaces for capturing images and video streams.
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.
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.
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.
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.
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.
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.
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.
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())
async
/await
for device operations to ensure non-blocking behavior.ONLINE
, OFFLINE
, ERROR
, BUSY
).disconnect
method.execute_command
method.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)python3 -m pip install unitapi
if multiple Python versions are installedsudo pip install unitapi
python3 -m venv unitapi_env
source unitapi_env/bin/activate # On Windows: unitapi_env\Scripts\activate
pip install unitapi
sudo apt-get install portaudio19-dev
pip install pyaudio
brew install portaudio
pip install pyaudio
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 .
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.
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())
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.
Logging: Use the logging module to provide informative logs for debugging.
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())
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.
scripts/ssh_connect.py
)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.
user@server
)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'
scripts/install_remote_keyboard_server.py
)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.
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
examples/ssh_connector_example.py
)A simple example script that demonstrates how to use the SSHConnector class to establish an SSH connection to a remote device and execute commands.
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 portThese tools require the following Python packages:
paramiko
: SSH implementation for Pythonpython-dotenv
: Loading environment variables from .env filesThese dependencies are included in the project’s requirements.txt
file.
The Python-based SSH tools offer several advantages over the bash-based scripts:
Potential future improvements for the SSH tools include:
UnitAPI provides a flexible framework for managing network-connected devices across different protocols and platforms.
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}")
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
You can easily extend UnitAPI by:
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 screenshotspip install unitapi
)pip install opencv-python
)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:
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:
The camera functionality can be integrated with other applications:
Remote camera control provides powerful capabilities but also introduces security risks. Consider the following:
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 remotelypip install unitapi
)pip install pyautogui
)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:
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:
The keyboard examples support the following operations:
The keyboard functionality can be integrated with other applications:
Remote keyboard control provides powerful capabilities but also introduces security risks. Consider the following:
release_all_keys
command to reset the keyboard stateThis 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:
The system consists of two main components:
remote_keyboard_server.py
): Runs on the Raspberry Pi and registers a keyboard device with the UnitAPI server.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:
For detailed installation instructions, see Remote Keyboard Server Installation Guide.
.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
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:
If you’re having trouble connecting to the Raspberry Pi:
.env
file is correctpython 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:
remote_keyboard_control_fixed.py
)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
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.
unitapi
python-dotenv
.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
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:
.env
file are correctYou can start the device discovery service on the Raspberry Pi with:
python examples/device_discovery.py
.env
fileThe script demonstrates:
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 controlpip install unitapi
)pip install pyaudio
)pip install numpy
)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:
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 loggingYou 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:
The examples support various audio formats:
The microphone functionality can be integrated with other applications:
Remote microphone control provides powerful capabilities but also introduces security risks. Consider the following:
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 devicesThe 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:
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:
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:
These miscellaneous examples can be combined with the device-specific examples to create more complex applications. For example:
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 controlpip install unitapi
)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:
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:
The mouse functionality can be integrated with other applications:
Remote mouse control provides powerful capabilities but also introduces security risks. Consider the following:
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 categoriesEach 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:
This architecture allows you to:
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
pip install unitapi
)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 loggingMost client examples support:
--host
: Server host to connect to (default: localhost)--port
: Server port to connect to (default: 7890)--debug
: Enable debug loggingWhen running servers that expose device functionality, consider the following security practices:
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 controlpip install unitapi
)pip install pyaudio
)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:
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 loggingYou 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:
The speaker functionality can be integrated with other 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:
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:
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:
/etc/unitapi/speaker_agent.json
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:
ssh user@remote-host 'sudo systemctl status unitapi-speaker-agent'
ssh user@remote-host 'sudo journalctl -u unitapi-speaker-agent'
ssh user@remote-host 'sudo cat /etc/unitapi/speaker_agent.json'
# 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
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 when auto_register_speakers
is false
)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:
The camera functionality can be integrated with other applications running on the Raspberry Pi. For example:
sudo raspi-config
Then navigate to “Interfacing Options” > “Camera” and enable it.
# 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
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)pip install unitapi
)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:
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.
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.
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 remotelypip install unitapi
)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:
--demo typing
): Demonstrates typing text and pressing Enter--demo hotkey
): Demonstrates using keyboard shortcuts like Ctrl+A--demo sequence
): Demonstrates using arrow keys and modifier keys--demo all
): Runs all demos in sequenceYou 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:
The keyboard functionality can be integrated with other applications running on the Raspberry Pi. For example:
Remote keyboard control provides powerful capabilities but also introduces security risks. Consider the following:
release_all_keys
command to reset the keyboard stateThis 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:
scripts/install_remote_keyboard_server.sh
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:
--trusted-host
flags./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.
.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
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:
ping <raspberry_pi_ip>
ssh <username>@<raspberry_pi_ip>
If using password authentication, ensure the password is correct.
chmod 600 ~/.ssh/id_rsa
If package installation fails:
Check the Raspberry Pi’s internet connection.
sudo apt-get update
If the service fails to start:
sudo systemctl status unitapi-keyboard.service
journalctl -u unitapi-keyboard.service
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 levelspip install unitapi
)pip install pyaudio
)ffmpeg
installedThe 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 loggingThe 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:
--demo record
): Records audio for a specified duration and saves it to a file--demo monitor
): Monitors audio levels in real-time and displays a level meter--demo vad
): Detects voice activity based on audio levelsThe microphone examples support the following operations:
The microphone examples support the following audio formats:
# List audio input devices
arecord -l
# Add user to audio group
sudo usermod -a -G audio $USER
# 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.
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 remotelypip install unitapi
)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:
--demo movement
): Demonstrates moving the mouse in patterns (square, circle)--demo click
): Demonstrates different types of mouse clicks (left, right, double)--demo scroll
): Demonstrates scrolling up and down--demo drag
): Demonstrates dragging operations--demo all
): Runs all demos in sequenceYou 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:
The mouse functionality can be integrated with other applications running on the Raspberry Pi. For example:
Remote mouse control provides powerful capabilities but also introduces security risks. Consider the following:
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_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_server.py
: Server for camera functionalitycamera_client.py
: Client for capturing images and videosmicrophone_server.py
: Server for microphone functionalitymicrophone_client.py
: Client for recording audio and monitoring levelsspeaker_server.py
: Server for speaker functionalityspeaker_client.py
: Client for audio playback and volume controlrespeaker_server.py
: Server for ReSpeaker functionalityrespeaker_client.py
: Client for audio recording, direction of arrival, and LED controlpip install unitapi
)picamera
or opencv-python
pyaudio
Adafruit_DHT
(for DHT11/DHT22 sensors)numpy
These examples follow a client-server architecture:
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.
gpio_server.py
)Exposes GPIO functionality through UnitAPI:
Usage:
# Run on the Raspberry Pi
python gpio/gpio_server.py --host 0.0.0.0 --port 7890
gpio_client.py
)Demonstrates basic GPIO pin control on Raspberry Pi, including:
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
led_control.py
)Advanced LED control examples for Raspberry Pi:
Usage:
# Connect to a local GPIO server
python gpio/led_control.py --demo rgb --rgb-mode fade --duration 10
sensors.py
)Demonstrates interfacing with various sensors connected to Raspberry Pi GPIO:
Usage:
# Connect to a local GPIO server
python gpio/sensors.py --demo dht --dht-pin 4 --dht-type DHT22
camera_server.py
)Exposes Raspberry Pi Camera Module functionality through UnitAPI:
Usage:
# Run on the Raspberry Pi
python camera/camera_server.py --host 0.0.0.0 --port 7890
camera_client.py
)Demonstrates using the Raspberry Pi Camera Module with UnitAPI:
Usage:
# Connect to a local server
python camera/camera_client.py --demo image --resolution 1920x1080
microphone_server.py
)Exposes microphone functionality through UnitAPI:
Usage:
# Run on the Raspberry Pi
python mic/microphone_server.py --host 0.0.0.0 --port 7890
microphone_client.py
)Demonstrates using the Raspberry Pi microphone with UnitAPI:
Usage:
# Connect to a local server
python mic/microphone_client.py --demo record --duration 10
speaker_server.py
)Exposes speaker functionality through UnitAPI:
Usage:
# Run on the Raspberry Pi
python speaker/speaker_server.py --host 0.0.0.0 --port 7890
speaker_client.py
)Demonstrates using the Raspberry Pi speaker with UnitAPI:
Usage:
# Connect to a local server
python speaker/speaker_client.py --demo file --audio-file sample.wav
respeaker_server.py
)Exposes ReSpeaker microphone array functionality through UnitAPI:
Usage:
# Run on the Raspberry Pi
python respeaker/respeaker_server.py --host 0.0.0.0 --port 7890
respeaker_client.py
)Demonstrates using the ReSpeaker microphone array with UnitAPI:
Usage:
# Connect to a local server
python respeaker/respeaker_client.py --demo voice --duration 30
The client and server communicate using the UnitAPI protocol:
This architecture allows for:
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.
sudo python gpio/gpio_server.py
sudo raspi-config
Then navigate to “Interfacing Options” > “Camera” and enable it.
# 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
# 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
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 arraypip install unitapi
)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:
--demo voice
): Records audio with beamforming and saves it to a file--demo doa
): Continuously displays the direction of sound sources--demo led
): Demonstrates various LED patterns on the ReSpeaker’s LED ring--demo all
): Runs all demos in sequenceThe ReSpeaker examples support the following operations:
These examples support the following ReSpeaker models:
# Check if ReSpeaker is detected
arecord -l
# Update your system first
sudo apt-get update
sudo apt-get upgrade
# Then reinstall the drivers
cd seeed-voicecard
sudo ./install.sh
sudo reboot
# 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.
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 volumepip install unitapi
)pip install pyaudio
)ffmpeg
installedThe 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:
--demo file
): Plays an audio file--demo tone
): Generates and plays a tone with specified frequency--demo volume
): Demonstrates volume control--demo all
): Runs all demos in sequenceThe speaker examples support the following operations:
The speaker examples support the following audio formats:
# List audio output devices
aplay -l
# Check and adjust volume
amixer sset 'Master' 80%
# Add user to audio group
sudo usermod -a -G audio $USER
# 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.
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:
This setup simulates a real-world scenario where you have a remote PC with speakers that you want to control from another PC.
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
speaker-server
container creates virtual speakers and exposes them through the UnitAPI protocol.speaker-client
container connects to the server via SSH and installs the UnitAPI speaker agent.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:
docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --list
docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --test
docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --device virtual_speaker_1
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:
docker-compose ps
docker-compose logs -f
docker exec -it unitapi-speaker-client ping 172.28.1.2
docker exec -it unitapi-speaker-server service ssh status
docker exec -it unitapi-speaker-server ps aux | grep unitapi
You can extend this example to include more features:
VIRTUAL_SPEAKERS
environment variable.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.
```bash ✍ tree -L 4 src
```bash
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