UnitAPI: Universal Hardware Interface as Network Devices

UnitAPI: Universal Hardware Interface as Network Devices

Overview

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.

Key Features

1. Device Management

2. Communication Protocols

3. Security

4. Device Types

Architecture

High-Level Architecture

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

Component Diagram

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

Device Inheritance Structure

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()
    }

Communication Sequence

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

Device Discovery Process

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]

Device Connection Lifecycle

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 --> [*]

Deployment Architecture

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

Network Topology

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

Implementation Timeline

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

Device Type Distribution

pie title Device Types in Typical Deployment
    "Cameras" : 25
    "Microphones" : 20
    "Speakers" : 20
    "Input Devices" : 15
    "GPIO Controllers" : 10
    "Custom Devices" : 10

User Experience Journey

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

Quick Start

Installation

pip install unitapi

Optional Protocol Support

# Install with specific protocol support
pip install unitapi[mqtt]
pip install unitapi[websocket]

Basic Usage

Server Setup

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()

Client Interaction

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)

Core Concepts

1. Devices

2. Protocols

3. Security

Use Cases

Documentation Sections

  1. Installation Guide
  2. Usage Guide
  3. Device Types
  4. Protocols
  5. Security
  6. Examples
  7. Remote Speaker Agent

Contributing

We welcome contributions! Please read our Contribution Guidelines for details on how to get started.

Support

License

UnitAPI is open-source software licensed under the MIT License.

Version

Current Version: 0.1.5

Compatibility

Performance Characteristics

Roadmap

Upcoming Features

Disclaimer

UnitAPI is an evolving project. While we strive for stability, the API may change in future versions.

Acknowledgments

Thanks to all contributors and the open-source community for making this project possible.

UnitAPI Device Types

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.

Overview

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:

Built-in Device Types

1. Camera Devices

Camera devices provide interfaces for capturing images and video streams.

Features

Example Usage

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())

2. Microphone Devices

Microphone devices provide interfaces for recording audio.

Features

Example Usage

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())

3. GPIO Devices

GPIO (General Purpose Input/Output) devices provide interfaces for controlling digital pins, typically on devices like Raspberry Pi.

Features

Example Usage

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())

4. Speaker Devices

Speaker devices provide interfaces for playing audio.

Features

Example Usage

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())

5. Mouse Devices

Mouse devices provide interfaces for controlling cursor movement and button actions.

Features

Example Usage

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())

6. Keyboard Devices

Keyboard devices provide interfaces for simulating keyboard input.

Features

Example Usage

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())

7. Touchscreen Devices

Touchscreen devices provide interfaces for simulating touch input.

Features

Example Usage

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())

8. Gamepad Devices

Gamepad devices provide interfaces for simulating game controller input.

Features

Example Usage

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())

Creating Custom Device Types

You can create custom device types by inheriting from the BaseDevice class or one of its subclasses.

Basic Custom Device

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)}

Custom Sensor Device

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)}

Device Registration

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())

Device Discovery

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())

Best Practices

  1. Asynchronous Operations: Always use async/await for device operations to ensure non-blocking behavior.
  2. Error Handling: Implement proper error handling in all device methods.
  3. Logging: Use the logging module to provide informative logs for debugging.
  4. Status Management: Keep the device status updated (ONLINE, OFFLINE, ERROR, BUSY).
  5. Resource Cleanup: Ensure proper cleanup in the disconnect method.
  6. Metadata: Use metadata to store device-specific configuration and capabilities.
  7. Command Interface: Implement a consistent command interface through the execute_command method.

UnitAPI Installation Guide

Prerequisites

Installation Methods

pip install unitapi

2. Optional Protocol Support

# Install with MQTT support
pip install unitapi[mqtt]

# Install with WebSocket support
pip install unitapi[websocket]

3. From Source

# 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 .

Verification

To verify the installation, run:

python -c "import unitapi; print(unitapi.__version__)"

Dependencies

Core Dependencies

Optional Dependencies

Troubleshooting

Common Installation Issues

  1. Python Version Compatibility
    • Ensure you’re using Python 3.8 or newer
    • Use python3 -m pip install unitapi if multiple Python versions are installed
  2. Permission Issues
    • On Unix-like systems, use sudo pip install unitapi
    • Recommended: Use virtual environments
  3. Dependency Conflicts
    • Create a virtual environment before installation
      python3 -m venv unitapi_env
      source unitapi_env/bin/activate  # On Windows: unitapi_env\Scripts\activate
      pip install unitapi
      
  4. PyAudio Installation Issues
    • On Linux, you may need to install PortAudio development headers:
      sudo apt-get install portaudio19-dev
      pip install pyaudio
      
    • On macOS, you can use Homebrew:
      brew install portaudio
      pip install pyaudio
      
    • On Windows, you might need to install a pre-built wheel:
      pip install pipwin
      pipwin install pyaudio
      

Development Installation

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 .

System-Specific Notes

Raspberry Pi

Docker

FROM python:3.9-slim

# Install UnitAPI
RUN pip install unitapi

# Optional: Install additional protocol support
RUN pip install unitapi[mqtt,websocket]

Updating UnitAPI

# Upgrade to latest version
pip install --upgrade unitapi

# Upgrade with specific protocol support
pip install --upgrade unitapi[mqtt]

Uninstallation

pip uninstall unitapi

Remote Speaker Agent Installation

For installing the Remote Speaker Agent on a remote machine, see the Remote Speaker Agent documentation.

Quick Remote Installation

# 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;'>&#x270D;</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())

Example Usage (Server)

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())

2. MQTT Protocol

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.

Features

Example Usage

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())

Protocol Selection

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())

Creating Custom Protocols

You can create custom protocols by implementing the necessary methods for your specific communication needs.

Basic Custom Protocol

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}")

Protocol Interoperability

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.

Example: Cross-Protocol Communication

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())

Best Practices

  1. Protocol Selection: Choose the appropriate protocol based on your application’s requirements:
    • WebSocket for real-time, bidirectional communication
    • MQTT for lightweight, publish-subscribe messaging in IoT applications
  2. Error Handling: Implement proper error handling for connection, disconnection, and message sending/receiving.

  3. Message Handlers: Use message handlers to process incoming messages asynchronously.

  4. Connection Management: Ensure proper connection and disconnection to avoid resource leaks.

  5. Security: Consider security implications when selecting and implementing protocols:
    • Use secure variants (WSS for WebSocket, MQTTS for MQTT)
    • Implement authentication and authorization
    • Encrypt sensitive data
  6. Logging: Use the logging module to provide informative logs for debugging.

  7. Asynchronous Operations: Always use async/await for protocol operations to ensure non-blocking behavior.

UnitAPI Security

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.

Overview

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.

Authentication

UnitAPI provides a flexible authentication system that supports various authentication methods.

Token-based Authentication

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())

Integrating Authentication with Server

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())

Client Authentication

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())

Access Control

UnitAPI implements a role-based access control system that allows fine-grained control over device operations.

Access Control Manager

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())

Integrating Access Control with Server

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())

Encryption

UnitAPI provides encryption utilities to secure sensitive data.

Data Encryption

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())

Secure Communication

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())

Audit Logging

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())

Security Best Practices

1. Authentication and Authorization

2. Secure Communication

3. Device Security

4. Audit and Monitoring

5. Secure Deployment

Secure Configuration Example

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())

Conclusion

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.

SSH Tools for UnitAPI

This document describes the SSH tools available in the UnitAPI project for connecting to and managing remote devices.

Overview

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.

Available Tools

1. SSH Connector (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.

Features

Usage

python scripts/ssh_connect.py [user@server] [password] [options]

Options

Examples

# 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'

2. Remote Keyboard Server Installer (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.

Features

Usage

python scripts/install_remote_keyboard_server.py [options]

Options

Examples

# 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

3. SSH Connector Example (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.

Features

Usage

python examples/ssh_connector_example.py

Example Output

=== 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

Environment Variables

All tools support loading configuration from a .env file. The following environment variables are recognized:

SSH Connector

Remote Keyboard Server Installer

Dependencies

These tools require the following Python packages:

These dependencies are included in the project’s requirements.txt file.

Comparison with Bash Scripts

The Python-based SSH tools offer several advantages over the bash-based scripts:

  1. Cross-platform compatibility: Works on Windows, macOS, and Linux
  2. Better error handling: More robust error detection and reporting
  3. Object-oriented design: Modular and reusable components
  4. Enhanced security: Better handling of credentials and connections
  5. Improved maintainability: Easier to extend and modify

Future Improvements

Potential future improvements for the SSH tools include:

  1. Support for SSH tunneling
  2. Integration with other UnitAPI components
  3. GUI interface for connection management
  4. Support for additional authentication methods
  5. Batch command execution

UnitAPI Usage Guide

Basic Concepts

UnitAPI provides a flexible framework for managing network-connected devices across different protocols and platforms.

Core Components

Quick Start

Starting a Server

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()

Client Interaction

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)

Device Types

Camera 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}")

Microphone Devices

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}")

GPIO Devices

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

Device Discovery

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()

Remote Speaker Agent

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'
    }
)

Authentication and Security

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')

Protocol Support

WebSocket Protocol

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()

MQTT Protocol

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)

Docker Support

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

Error Handling

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}")

Best Practices

  1. Always use async/await for device operations
  2. Implement proper error handling
  3. Use authentication and access control
  4. Keep sensitive information secure
  5. Monitor device states and connections
  6. Use device discovery for automatic setup

Logging

import logging

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

Extensibility

You can easily extend UnitAPI by:

PC Camera Examples for UnitAPI

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.

Files

Prerequisites

Local Camera Control

The camera client examples demonstrate how to use the camera device locally to capture images and record videos.

Running the Local Clients

# 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:

Remote Camera Control

The camera server and remote client examples demonstrate how to control a camera remotely using UnitAPI.

Running the Server

# 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:

Running the Remote Clients

# 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:

Supported Camera Operations

The camera examples support the following operations:

Integration with Other Applications

The camera functionality can be integrated with other applications:

Security Considerations

Remote camera control provides powerful capabilities but also introduces security risks. Consider the following:

Troubleshooting

  1. Camera Access Issues: Ensure the camera is not being used by another application
  2. Permission Issues: Some systems may require additional permissions for camera access
  3. Performance Issues: Adjust resolution and frame rate for better performance
  4. Format Compatibility: Ensure the image format is supported by your system

Example Use Cases

  1. Remote Monitoring: Monitor a location using a remote camera
  2. Computer Vision: Develop computer vision applications with remote camera input
  3. Automated Testing: Capture screenshots for visual regression testing
  4. Video Recording: Record video for documentation or tutorials
  5. Security: Create a simple security camera system

PC Keyboard Examples for UnitAPI

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.

Files

Prerequisites

Local Keyboard Control

The keyboard client demonstrates how to use the keyboard device locally to type text, press keys, and use keyboard shortcuts.

Running the Local Client

# Run the local keyboard example
python examples/pc/keyboard/keyboard_client.py

This example demonstrates:

Remote Keyboard Control

The keyboard server and remote client demonstrate how to control a keyboard remotely using UnitAPI.

Running the Server

# Run on the PC you want to control
python examples/pc/keyboard/keyboard_server.py --host 0.0.0.0 --port 7890

Options:

Running the Remote Client

# 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:

Demo Modes

The remote client provides several demo modes:

  1. Typing Demo: Demonstrates typing text and pressing Enter
  2. Hotkey Demo: Demonstrates using keyboard shortcuts like Ctrl+A
  3. Key Sequence Demo: Demonstrates using arrow keys and modifier keys
  4. All Demos: Runs all demos in sequence

Supported Keyboard Operations

The keyboard examples support the following operations:

Integration with Other Applications

The keyboard functionality can be integrated with other applications:

Security Considerations

Remote keyboard control provides powerful capabilities but also introduces security risks. Consider the following:

Troubleshooting

  1. Connection Issues: Ensure the server is running and accessible from the client’s network
  2. Permission Issues: Some systems may require additional permissions for keyboard control
  3. Key Mapping Issues: Different keyboard layouts may require adjustments to key mappings
  4. Stuck Keys: If keys appear to be stuck, use the release_all_keys command to reset the keyboard state

Example Use Cases

  1. Remote Control: Control applications on a headless PC
  2. Automation: Automate repetitive keyboard tasks
  3. Kiosk Systems: Implement controlled keyboard input for kiosk applications
  4. Accessibility: Create custom keyboard interfaces for accessibility purposes

Remote Keyboard Control

This directory contains scripts for controlling a keyboard on a remote Raspberry Pi device.

Overview

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:

Components

The system consists of two main components:

  1. Server (remote_keyboard_server.py): Runs on the Raspberry Pi and registers a keyboard device with the UnitAPI server.
  2. Client (remote_keyboard_control_fixed.py): Runs on your computer and sends keyboard commands to the server.

Installation

Server Installation (on Raspberry Pi)

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.

Client Configuration (on your computer)

  1. Update your .env file with the Raspberry Pi connection details:
RPI_HOST=192.168.1.100  # Replace with your Raspberry Pi's IP address
RPI_USER=pi             # Replace with your Raspberry Pi username
RPI_PASSWORD=raspberry  # Replace with your Raspberry Pi password
  1. Make sure you have the required Python packages installed:
pip install -r requirements.txt

Usage

Basic Usage

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

Running the Demo

To run a demo sequence that demonstrates various keyboard actions:

python examples/remote_keyboard_control_fixed.py

This will:

  1. List available keyboards on the Raspberry Pi
  2. Type some text
  3. Press Enter
  4. Type more text
  5. Press Ctrl+A to select all text

Troubleshooting

Connection Issues

If you’re having trouble connecting to the Raspberry Pi:

  1. Check that the Raspberry Pi is powered on and connected to the network
  2. Verify that the IP address in your .env file is correct
  3. Make sure the UnitAPI server is running on the Raspberry Pi
  4. Check the server status:
python scripts/ssh_connect_wrapper.sh <username>@<raspberry_pi_ip> <password> -c 'systemctl status unitapi-keyboard.service'

Local Keyboard Control Issue

If the script is controlling your local keyboard instead of the remote one:

  1. Make sure you’re using the fixed version of the client script (remote_keyboard_control_fixed.py)
  2. Check that the connection to the remote server is successful
  3. Verify that the keyboard device is registered on the remote server

Advanced Configuration

Custom Keyboard Device

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"

Multiple Keyboards

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

Security Considerations

Further Reading

Remote Keyboard Control Example

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.

Prerequisites

  1. A Raspberry Pi with UnitAPI server installed and running
  2. Python 3.6+ on both the client and Raspberry Pi
  3. Required Python packages:
    • unitapi
    • python-dotenv

Setup

  1. Make sure the UnitAPI server is running on your Raspberry Pi
  2. Update the .env file with your Raspberry Pi connection details:
    RPI_HOST=192.168.1.100  # Replace with your Raspberry Pi's IP address
    RPI_USER=pi             # Replace with your Raspberry Pi username
    RPI_PASSWORD=raspberry  # Replace with your Raspberry Pi password
    
  3. Make sure the keyboard device is registered on the Raspberry Pi UnitAPI server

Usage

List available keyboards on the remote device

python examples/remote_keyboard_control.py --list

Type text on a specific keyboard

python examples/remote_keyboard_control.py --device-id keyboard_01 --text "Hello, world!"

Press a key on a specific keyboard

python examples/remote_keyboard_control.py --device-id keyboard_01 --key "enter"

Press a hotkey combination on a specific keyboard

python examples/remote_keyboard_control.py --device-id keyboard_01 --hotkey "ctrl,a"

Run a demo sequence

If no specific action is provided, the script will run a demo sequence on the first available keyboard:

python examples/remote_keyboard_control.py

Troubleshooting

If no keyboards are found, make sure:

  1. The UnitAPI server is running on your Raspberry Pi
  2. The keyboard device is registered with the server
  3. The connection details in the .env file are correct
  4. There are no network issues preventing connection to the Raspberry Pi

You can start the device discovery service on the Raspberry Pi with:

python examples/device_discovery.py

How It Works

  1. The script loads connection details from the .env file
  2. It connects to the UnitAPI server on the Raspberry Pi
  3. It lists available keyboard devices or performs the specified action
  4. Commands are sent to the remote keyboard device through the UnitAPI client

The script demonstrates:

PC Microphone Examples for UnitAPI

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.

Files

Prerequisites

Local Microphone Control

The microphone client examples demonstrate how to use the microphone device locally to record audio and capture audio input.

Running the Local Clients

# 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:

Remote Microphone Control

The microphone server allows remote clients to control the microphone on a PC using UnitAPI.

Running the Server

# 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:

Connecting to the Server

You can connect to the microphone server using the UnitAPI client:

from unitapi.core.client import UnitAPIClient

async def control_remote_microphone():
    # Connect to the server
    client = UnitAPIClient(server_host="192.168.1.100", server_port=7890)
    
    # List available devices
    devices = await client.list_devices()
    
    # Find the microphone device
    mic_devices = [d for d in devices if d.get('type') == 'microphone']
    if not mic_devices:
        print("No microphone devices found")
        return
    
    mic_device = mic_devices[0]
    device_id = mic_device.get('device_id')
    
    # Start recording
    result = await client.execute_command(
        device_id=device_id,
        command="start_recording",
        params={
            "sample_rate": 44100,
            "channels": 1,
            "format": "wav",
            "output_file": "remote_recording.wav",
            "duration": 10  # Record for 10 seconds
        }
    )
    
    recording_id = result.get('recording_id')
    
    # Get audio level
    level_result = await client.execute_command(
        device_id=device_id,
        command="get_audio_level",
        params={}
    )
    
    print(f"Audio level: {level_result.get('level')}")
    
    # Wait for recording to complete
    await asyncio.sleep(10)
    
    # Stop recording manually if no duration was specified
    # await client.execute_command(
    #     device_id=device_id,
    #     command="stop_recording",
    #     params={"recording_id": recording_id}
    # )

Supported Microphone Operations

The microphone examples support the following operations:

Audio Format Support

The examples support various audio formats:

Integration with Other Applications

The microphone functionality can be integrated with other applications:

Security Considerations

Remote microphone control provides powerful capabilities but also introduces security risks. Consider the following:

Troubleshooting

  1. Microphone Access Issues: Ensure the microphone is not being used by another application
  2. Permission Issues: Some systems may require additional permissions for microphone access
  3. PyAudio Installation: On some systems, PyAudio may require additional dependencies
  4. FFmpeg Missing: For non-WAV formats, ensure FFmpeg is installed and available in the system path

Example Use Cases

  1. Voice Recording: Record voice for documentation or dictation
  2. Audio Monitoring: Monitor audio levels in an environment
  3. Speech Recognition: Capture audio for speech-to-text processing
  4. Sound Detection: Detect specific sounds or noise levels
  5. Remote Conferencing: Implement remote audio capture for conferencing applications

Miscellaneous PC Examples for UnitAPI

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.

Files

Device Discovery

The device discovery example shows how to find UnitAPI devices on the network. This is useful for discovering available devices without knowing their specific addresses.

Running the Device Discovery Example

# Run the device discovery example
python examples/pc/misc/device_discovery.py

This example demonstrates:

SSH Connector

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.

Running the SSH Connector Example

# Run the SSH connector example
python examples/pc/misc/ssh_connector.py --host remote-host --user username

Options:

This example demonstrates:

Input Devices

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.

Running the Input Devices Example

# Run the input devices example
python examples/pc/misc/input_devices.py

This example demonstrates:

Integration with Other Examples

These miscellaneous examples can be combined with the device-specific examples to create more complex applications. For example:

  1. Use device discovery to find available devices
  2. Connect to remote devices using SSH
  3. Control specific devices using the device-specific examples

Additional Resources

For more information about UnitAPI and its capabilities, see the documentation in the docs/ directory.

PC Mouse Examples for UnitAPI

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.

Files

Prerequisites

Local Mouse Control

The mouse client demonstrates how to use the mouse device locally to move the cursor, click, and perform other mouse operations.

Running the Local Client

# 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:

Remote Mouse Control

The mouse server allows remote clients to control the mouse on a PC using UnitAPI.

Running the Server

# Run on the PC you want to control
python examples/pc/mouse/mouse_server.py --host 0.0.0.0 --port 7890

Options:

Connecting to the Server

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"}
    )

Supported Mouse Operations

The mouse examples support the following operations:

Integration with Other Applications

The mouse functionality can be integrated with other applications:

Security Considerations

Remote mouse control provides powerful capabilities but also introduces security risks. Consider the following:

Troubleshooting

  1. Connection Issues: Ensure the server is running and accessible from the client’s network
  2. Permission Issues: Some systems may require additional permissions for mouse control
  3. Coordinate Issues: Screen resolutions may differ between systems, affecting absolute positioning
  4. Performance Issues: High latency networks may affect the responsiveness of mouse control

Example Use Cases

  1. Remote Control: Control applications on a headless PC
  2. Automation: Automate repetitive mouse tasks
  3. Kiosk Systems: Implement controlled mouse input for kiosk applications
  4. Accessibility: Create custom mouse interfaces for accessibility purposes
  5. Testing: Automate GUI testing with programmatic mouse control

PC Examples for UnitAPI

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.

Directory Structure

Device Types

Each subdirectory contains examples for a specific device type:

Camera Examples

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.

Keyboard Examples

The keyboard/ directory contains examples for working with keyboards. These examples demonstrate how to send keystrokes, handle keyboard events, and control keyboards remotely.

Microphone Examples

The microphone/ directory contains examples for working with microphones. These examples demonstrate how to record audio, process microphone input, and measure audio levels.

Mouse Examples

The mouse/ directory contains examples for working with mice. These examples demonstrate how to control mouse movements, handle mouse clicks, and automate mouse actions.

Speaker Examples

The speaker/ directory contains examples for working with speakers. These examples demonstrate how to play audio files, generate sounds, and control audio playback.

Client-Server Architecture

Many examples follow a client-server architecture:

This architecture allows you to:

  1. Control devices on remote machines
  2. Create distributed applications
  3. Implement device sharing and remote access
  4. Build automation systems that span multiple devices

Running the Examples

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

Prerequisites

Common Options

Most server examples support the following command-line options:

Most client examples support:

Security Considerations

When running servers that expose device functionality, consider the following security practices:

  1. Run servers on secure, private networks
  2. Use UnitAPI’s authentication and encryption features
  3. Implement appropriate access controls
  4. Be cautious about exposing sensitive devices to remote access

Additional Resources

For more information about UnitAPI and its capabilities, see the documentation in the docs/ directory.

PC Speaker Examples for UnitAPI

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.

Files

Prerequisites

Local Speaker Control

The speaker client examples demonstrate how to use the speaker device locally to play audio files and generate sounds.

Running the Local Clients

# 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:

Remote Speaker Control

The speaker server allows remote clients to control the speakers on a PC using UnitAPI.

Running the Server

# 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:

Connecting to the Server

You can connect to the speaker server using the UnitAPI client:

from unitapi.core.client import UnitAPIClient

async def control_remote_speaker():
    # Connect to the server
    client = UnitAPIClient(server_host="192.168.1.100", server_port=7890)
    
    # List available devices
    devices = await client.list_devices()
    
    # Find the speaker device
    speaker_devices = [d for d in devices if d.get('type') == 'speaker']
    if not speaker_devices:
        print("No speaker devices found")
        return
    
    speaker_device = speaker_devices[0]
    device_id = speaker_device.get('device_id')
    
    # Play audio file
    await client.execute_command(
        device_id=device_id,
        command="play_audio",
        params={
            "file_path": "path/to/audio.wav",
            "volume": 0.8
        }
    )
    
    # Generate a tone
    await client.execute_command(
        device_id=device_id,
        command="play_tone",
        params={
            "frequency": 440,  # A4 note
            "duration": 1.0,   # 1 second
            "volume": 0.5
        }
    )

Supported Audio Formats

The examples support various audio formats:

Integration with Other Applications

The speaker functionality can be integrated with other applications:

Troubleshooting

  1. Audio Device Issues: Ensure the audio device is properly configured and not in use by another application
  2. Format Support: Some audio formats may require additional libraries
  3. PyAudio Installation: On some systems, PyAudio may require additional dependencies
  4. Volume Control: If no sound is heard, check system volume and application volume settings

Example Use Cases

  1. Audio Playback: Play music or sound effects in applications
  2. Text-to-Speech: Convert text to speech for accessibility
  3. Notifications: Play alert sounds for system events
  4. Remote Control: Control audio playback on a remote system
  5. Sound Generation: Generate tones and sounds for testing or musical applications

UnitAPI Remote Speaker Agent

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.

Overview

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:

Installation

There are two ways to install the Remote Speaker Agent:

1. Direct Installation on the Remote Machine

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

2. Remote Installation via SSH

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:

  1. Connect to the remote machine via SSH
  2. Copy the installation script to the remote machine
  3. Execute the installation script on the remote machine
  4. Create a local client script for testing the remote speakers

Managing the Remote Speaker Agent

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'

Connecting to the Remote Speaker Agent

Using the Python Client

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())

Using the Command-Line Client

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

Docker Example

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.

Technical Details

The Remote Speaker Agent consists of the following components:

  1. UnitAPI Server: Handles device registration and communication
  2. WebSocket Server: Provides a WebSocket interface for real-time communication
  3. Speaker Detection: Automatically detects all speakers on the system
  4. Speaker Registry: Maintains a registry of all available speakers
  5. Configuration: Stores speaker configuration in /etc/unitapi/speaker_agent.json
  6. Systemd Service: Runs the agent as a system service (unitapi-speaker-agent)

The agent is installed in /opt/unitapi and runs in a Python virtual environment to avoid conflicts with system packages.

Troubleshooting

If you encounter issues with the Remote Speaker Agent, check the following:

  1. Service Status: Check if the service is running
    ssh user@remote-host 'sudo systemctl status unitapi-speaker-agent'
    
  2. Logs: Check the service logs
    ssh user@remote-host 'sudo journalctl -u unitapi-speaker-agent'
    
  3. Configuration: Check the configuration file
    ssh user@remote-host 'sudo cat /etc/unitapi/speaker_agent.json'
    
  4. Network: Make sure the remote machine is reachable and the required ports are open
    # Test connectivity
    ping remote-host
       
    # Test if the UnitAPI port is open
    nc -zv remote-host 7890
       
    # Test if the WebSocket port is open
    nc -zv remote-host 8765
    
  5. Dependencies: Make sure all required dependencies are installed
    ssh user@remote-host 'sudo /opt/unitapi/venv/bin/pip list | grep -E "pyaudio|websockets|numpy|sounddevice|soundfile"'
    

Advanced Usage

Custom Configuration

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:

Multiple Remote Machines

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

Integration with Other UnitAPI Devices

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;'>&#x270D;</span>](git@github.com:UnitApi/python/edit/main/examples/README_remote_keyboard_fixed.md)


 [<span style='font-size:20px;'>&#x270D;</span>](git@github.com:UnitApi/python/edit/main/examples/README_remote_keyboard.md)


 [<span style='font-size:20px;'>&#x270D;</span>](git@github.com:UnitApi/python/edit/main/examples/remote_keyboard_control.md)


 [<span style='font-size:20px;'>&#x270D;</span>](git@github.com:UnitApi/python/edit/main/examples/remote_keyboard_server_installation.md)


 [<span style='font-size:20px;'>&#x270D;</span>](git@github.com:UnitApi/python/edit/main/examples/remote_speaker_agent.md)


# Raspberry Pi Camera Examples for UnitAPI [<span style='font-size:20px;'>&#x270D;</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:

Client Usage

The camera client connects to the server and controls the camera remotely. It provides methods for capturing images, recording videos, and applying image effects.

Running the Client

# 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:

Supported Camera Operations

The camera examples support the following operations:

Integration with Other Applications

The camera functionality can be integrated with other applications running on the Raspberry Pi. For example:

Troubleshooting

  1. Camera Not Detected: Ensure the camera module is properly connected and enabled in raspi-config:
    sudo raspi-config
    

    Then navigate to “Interfacing Options” > “Camera” and enable it.

  2. Permission Issues: Some systems may require additional permissions for camera access
    # Add user to video group
    sudo usermod -a -G video $USER
    
  3. Connection Issues: Ensure the server is running and accessible from the client’s network

  4. Performance Issues: Lower the resolution or framerate if experiencing lag or high CPU usage

Example Use Cases

  1. Security Camera: Set up a remote security camera with motion detection
  2. Timelapse Photography: Create timelapse videos of plants growing, construction projects, etc.
  3. Computer Vision: Use the camera for object detection, face recognition, or other computer vision tasks
  4. Remote Monitoring: Monitor a location remotely using the camera

Raspberry Pi GPIO Examples for UnitAPI

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.

Files

Prerequisites

Server Setup

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.

Running the Server

# Run on the Raspberry Pi
python gpio_server.py --host 0.0.0.0 --port 7890

Options:

Client Usage

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.

Running the GPIO Control Client

# 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:

Running the LED Control Client

# 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:

Running the Sensors Client

# 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:

Supported GPIO Operations

The GPIO examples support the following operations:

GPIO Pin Numbering

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.

Safety Considerations

Troubleshooting

  1. Permission Issues: If you encounter permission errors when accessing GPIO pins, try running the server with sudo:
    sudo python gpio_server.py
    
  2. 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.

  3. Connection Issues: Ensure the server is running and accessible from the client’s network.

  4. Wiring Issues: Double-check your wiring connections. Use a multimeter to verify connections if necessary.

Example Use Cases

  1. Home Automation: Control lights, fans, and other appliances remotely
  2. Environmental Monitoring: Monitor temperature, humidity, and other environmental conditions
  3. Security Systems: Create motion detection systems with PIR sensors
  4. Interactive Projects: Build interactive projects with buttons, LEDs, and displays

Raspberry Pi Keyboard Examples for UnitAPI

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.

Files

Prerequisites

Server Setup

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.

Running the Server

# Run on the Raspberry Pi
python keyboard_server.py --host 0.0.0.0 --port 7890

Options:

Client Usage

The keyboard client connects to the server and controls the keyboard remotely. It provides methods for typing text, pressing keys, and using keyboard shortcuts.

Running the Client

# 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:

Demo Modes

The client provides several demo modes:

  1. Typing Demo (--demo typing): Demonstrates typing text and pressing Enter
  2. Hotkey Demo (--demo hotkey): Demonstrates using keyboard shortcuts like Ctrl+A
  3. Key Sequence Demo (--demo sequence): Demonstrates using arrow keys and modifier keys
  4. All Demos (--demo all): Runs all demos in sequence

Custom Commands

You can also use the client to execute specific keyboard commands:

# Type specific text
python keyboard_client.py --text "Hello, world!"

# Press a specific key
python keyboard_client.py --key enter

# Press a specific hotkey combination
python keyboard_client.py --hotkey ctrl,s

Supported Keyboard Operations

The keyboard examples support the following operations:

Integration with Other Applications

The keyboard functionality can be integrated with other applications running on the Raspberry Pi. For example:

Security Considerations

Remote keyboard control provides powerful capabilities but also introduces security risks. Consider the following:

Troubleshooting

  1. Connection Issues: Ensure the server is running and accessible from the client’s network
  2. Permission Issues: Some systems may require additional permissions for keyboard control
  3. Key Mapping Issues: Different keyboard layouts may require adjustments to key mappings
  4. Stuck Keys: If keys appear to be stuck, use the release_all_keys command to reset the keyboard state

Example Use Cases

  1. Remote Control: Control applications on a headless Raspberry Pi
  2. Automation: Automate repetitive keyboard tasks
  3. Kiosk Systems: Implement controlled keyboard input for kiosk applications
  4. Accessibility: Create custom keyboard interfaces for accessibility purposes

Remote Keyboard Server Installation Guide

This document provides information about installing and configuring the UnitAPI Remote Keyboard Server on a Raspberry Pi.

Overview

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.

Installation Options

There are two installation scripts available:

  1. Standard Installation Script: scripts/install_remote_keyboard_server.sh
  2. Fixed Installation Script: scripts/install_remote_keyboard_server_fixed.sh (Recommended)

The fixed installation script includes several improvements to handle common installation issues.

Improvements in the Fixed Installation Script

The install_remote_keyboard_server_fixed.sh script includes the following improvements:

  1. Improved SSH Authentication:
    • Explicitly disables pubkey authentication when using password authentication to prevent “too many authentication failures” errors
    • Adds retry mechanism for SSH connections with configurable number of attempts
    • Provides better error messages for authentication failures
  2. Repository Handling:
    • Detects outdated Raspberry Pi OS versions (like “stretch”)
    • Updates repository sources to use archive repositories for outdated OS versions
    • Prevents 404 errors when accessing outdated repositories
  3. SSL Certificate Verification:
    • Disables SSL certificate verification for pip installations using --trusted-host flags
    • Resolves SSL certificate verification failures when installing Python packages
    • Adds trusted hosts for both PyPI and piwheels repositories
  4. Improved File Transfer:
    • Adds retry mechanism for SCP file transfers
    • Verifies successful file transfers before proceeding
    • Creates a local service file and transfers it directly to avoid path issues
  5. Error Handling and Recovery:
    • Adds retry mechanisms for package installation and unitapi installation
    • Continues installation even if some steps fail, with appropriate warnings
    • Provides more detailed error messages and status updates

Usage

Basic Installation

./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --password raspberry

Using SSH Key Authentication

./scripts/install_remote_keyboard_server_fixed.sh --host 192.168.1.100 --identity ~/.ssh/id_rsa

Controlling the Service

# 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

Client Configuration

After installing the Remote Keyboard Server on your Raspberry Pi, you need to configure the client to connect to it.

  1. Update your .env file with the following:
RPI_HOST=192.168.1.100  # Replace with your Raspberry Pi's IP address
RPI_USER=pi             # Replace with your Raspberry Pi username
RPI_PASSWORD=raspberry  # Replace with your Raspberry Pi password
  1. Run the client:
python examples/remote_keyboard_control_fixed.py

Note: We recommend using the fixed version of the client script (remote_keyboard_control_fixed.py) instead of the original version (remote_keyboard_control.py). The fixed version includes better error handling, connection checking, and troubleshooting guidance.

Client Script Options

The remote keyboard control client supports several command-line options:

python examples/remote_keyboard_control_fixed.py --help

Common options include:

Troubleshooting

SSH Connection Issues

If you’re experiencing SSH connection issues:

  1. Verify that the Raspberry Pi is reachable on the network:
    ping <raspberry_pi_ip>
    
  2. Check that SSH is enabled on the Raspberry Pi:
    ssh <username>@<raspberry_pi_ip>
    
  3. If using password authentication, ensure the password is correct.

  4. If using key-based authentication, ensure the key file exists and has the correct permissions:
    chmod 600 ~/.ssh/id_rsa
    

Package Installation Issues

If package installation fails:

  1. Check the Raspberry Pi’s internet connection.

  2. Try updating the package lists manually:
    sudo apt-get update
    
  3. If using an outdated Raspberry Pi OS version, consider upgrading to a newer version.

Service Issues

If the service fails to start:

  1. Check the service status:
    sudo systemctl status unitapi-keyboard.service
    
  2. Check the service logs:
    journalctl -u unitapi-keyboard.service
    
  3. Verify that the Python virtual environment was created correctly:
    ls -la /home/pi/unitapi/venv/bin/python
    

Python Installation Alternative

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.

Raspberry Pi Microphone Examples for UnitAPI

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.

Files

Prerequisites

Server Setup

The microphone server runs on the Raspberry Pi and exposes microphone functionality through UnitAPI. It registers a microphone device with the UnitAPI server and handles commands for audio recording and level monitoring.

Running the Server

# Run on the Raspberry Pi
python microphone_server.py --host 0.0.0.0 --port 7890

Options:

Client Usage

The microphone client connects to the server and controls the microphone remotely. It provides methods for recording audio and monitoring audio levels.

Running the Client

# 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:

Demo Modes

The client provides several demo modes:

  1. Record Demo (--demo record): Records audio for a specified duration and saves it to a file
  2. Monitor Demo (--demo monitor): Monitors audio levels in real-time and displays a level meter
  3. Voice Activity Detection Demo (--demo vad): Detects voice activity based on audio levels

Supported Microphone Operations

The microphone examples support the following operations:

Audio Formats

The microphone examples support the following audio formats:

Troubleshooting

  1. Microphone Not Detected: Ensure the microphone is properly connected and recognized by the system:
    # List audio input devices
    arecord -l
    
  2. Permission Issues: Some systems may require additional permissions for audio access:
    # Add user to audio group
    sudo usermod -a -G audio $USER
    
  3. PyAudio Installation Issues: If you have trouble installing PyAudio, try:
    # Install dependencies
    sudo apt-get install portaudio19-dev python3-pyaudio
       
    # Then install PyAudio
    pip install pyaudio
    
  4. Audio Quality Issues: If you experience poor audio quality, try adjusting the sample rate or using a different microphone.

  5. Connection Issues: Ensure the server is running and accessible from the client’s network.

Example Use Cases

  1. Voice Assistant: Create a voice-controlled assistant using the microphone for input
  2. Audio Monitoring: Monitor sound levels in a room or environment
  3. Voice Recording: Record voice memos or audio notes remotely
  4. Sound Detection: Create a system that responds to specific sounds or noise levels
  5. Voice Activity Detection: Trigger actions when voice activity is detected

Raspberry Pi Mouse Examples for UnitAPI

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.

Files

Prerequisites

Server Setup

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.

Running the Server

# Run on the Raspberry Pi
python mouse_server.py --host 0.0.0.0 --port 7890

Options:

Client Usage

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.

Running the Client

# 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:

Demo Modes

The client provides several demo modes:

  1. Movement Demo (--demo movement): Demonstrates moving the mouse in patterns (square, circle)
  2. Click Demo (--demo click): Demonstrates different types of mouse clicks (left, right, double)
  3. Scroll Demo (--demo scroll): Demonstrates scrolling up and down
  4. Drag Demo (--demo drag): Demonstrates dragging operations
  5. All Demos (--demo all): Runs all demos in sequence

Custom Commands

You can also use the client to execute specific mouse commands:

# Move to specific coordinates
python mouse_client.py --x 500 --y 500

# Move by a relative amount
python mouse_client.py --dx 100 --dy -50

# Click a specific button
python mouse_client.py --button right

# Scroll up or down
python mouse_client.py --scroll-amount 10

Supported Mouse Operations

The mouse examples support the following operations:

Integration with Other Applications

The mouse functionality can be integrated with other applications running on the Raspberry Pi. For example:

Security Considerations

Remote mouse control provides powerful capabilities but also introduces security risks. Consider the following:

Troubleshooting

  1. Connection Issues: Ensure the server is running and accessible from the client’s network
  2. Permission Issues: Some systems may require additional permissions for mouse control
  3. Coordinate Issues: Screen coordinates are relative to the Raspberry Pi’s display resolution
  4. Performance Issues: Reduce the frequency of mouse operations if experiencing lag

Example Use Cases

  1. Remote Control: Control applications on a headless Raspberry Pi
  2. Automation: Automate repetitive mouse tasks
  3. Kiosk Systems: Implement controlled mouse input for kiosk applications
  4. Accessibility: Create custom mouse interfaces for accessibility purposes

Raspberry Pi Examples for UnitAPI

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.

Directory Structure

The examples are organized by device type:

Prerequisites

Server and Client Architecture

These examples follow a client-server architecture:

  1. Server: Runs on the Raspberry Pi and exposes hardware functionality through UnitAPI
  2. Client: Connects to the server and controls the hardware remotely

Running the Servers

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.

Examples Overview

1. GPIO Examples (gpio/)

Server (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

Client (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 (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 (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

2. Camera Examples (camera/)

Server (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

Client (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

3. Microphone Examples (mic/)

Server (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

Client (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

4. Speaker Examples (speaker/)

Server (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

Client (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

5. ReSpeaker Examples (respeaker/)

Server (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

Client (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

Hardware Requirements

GPIO Examples

Camera Examples

Microphone Examples

Speaker Examples

ReSpeaker Examples

Client-Server Communication

The client and server communicate using the UnitAPI protocol:

  1. The server registers devices and command handlers
  2. The client connects to the server and discovers available devices
  3. The client sends commands to control the devices
  4. The server executes the commands and returns the results

This architecture allows for:

GPIO Pin Numbering

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.

Troubleshooting

  1. Permission Issues: If you encounter permission errors when accessing hardware, try running the server with sudo:
    sudo python gpio/gpio_server.py
    
  2. Camera Not Detected: Ensure the camera module is properly connected and enabled in raspi-config:
    sudo raspi-config
    

    Then navigate to “Interfacing Options” > “Camera” and enable it.

  3. Audio Issues: If you have issues with audio input/output:
    # List audio devices
    arecord -l  # Input devices
    aplay -l    # Output devices
       
    # Test microphone recording
    arecord -d 5 -f cd test.wav
       
    # Test speaker playback
    aplay test.wav
    
  4. ReSpeaker Issues: For ReSpeaker setup problems:
    # Check if ReSpeaker is detected
    lsusb
       
    # Install ReSpeaker drivers if needed
    git clone https://github.com/respeaker/seeed-voicecard
    cd seeed-voicecard
    sudo ./install.sh
    sudo reboot
    
  5. Server Connection Issues: If the client cannot connect to the server, check:
    • The server is running and listening on the correct interface (0.0.0.0 for all interfaces)
    • The port is not blocked by a firewall
    • The host and port in the client match the server
    • Network connectivity between client and server

Safety Warnings

Raspberry Pi ReSpeaker Examples for UnitAPI

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.

Files

Prerequisites

ReSpeaker Setup

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

Server Setup

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.

Running the Server

# Run on the Raspberry Pi
python respeaker_server.py --host 0.0.0.0 --port 7890

Options:

Client Usage

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.

Running the Client

# 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:

Demo Modes

The client provides several demo modes:

  1. Voice Demo (--demo voice): Records audio with beamforming and saves it to a file
  2. Direction of Arrival Demo (--demo doa): Continuously displays the direction of sound sources
  3. LED Demo (--demo led): Demonstrates various LED patterns on the ReSpeaker’s LED ring
  4. All Demos (--demo all): Runs all demos in sequence

Supported ReSpeaker Operations

The ReSpeaker examples support the following operations:

ReSpeaker Models

These examples support the following ReSpeaker models:

Troubleshooting

  1. ReSpeaker Not Detected: Ensure the ReSpeaker is properly connected and the drivers are installed:
    # Check if ReSpeaker is detected
    arecord -l
    
  2. Driver Installation Issues: If you have trouble installing the drivers, try:
    # Update your system first
    sudo apt-get update
    sudo apt-get upgrade
       
    # Then reinstall the drivers
    cd seeed-voicecard
    sudo ./install.sh
    sudo reboot
    
  3. LED Control Issues: If the LEDs don’t work, check if the SPI interface is enabled:
    # Enable SPI interface
    sudo raspi-config
    # Navigate to "Interfacing Options" > "SPI" and enable it
    
  4. Audio Quality Issues: If you experience poor audio quality, try adjusting the microphone gain or using a different beamforming algorithm.

  5. Connection Issues: Ensure the server is running and accessible from the client’s network.

Example Use Cases

  1. Voice Assistant: Create a voice-controlled assistant with directional awareness
  2. Sound Localization: Determine the direction of sound sources in a room
  3. Interactive LED Feedback: Provide visual feedback through the LED ring based on sound direction
  4. Multi-Room Audio: Create a distributed audio recording system with multiple ReSpeakers
  5. Conference Room System: Build a smart conference room system with directional audio recording

Raspberry Pi Speaker Examples for UnitAPI

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.

Files

Prerequisites

Server Setup

The speaker server runs on the Raspberry Pi and exposes speaker functionality through UnitAPI. It registers a speaker device with the UnitAPI server and handles commands for audio playback and volume control.

Running the Server

# Run on the Raspberry Pi
python speaker_server.py --host 0.0.0.0 --port 7890

Options:

Client Usage

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.

Running the Client

# 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:

Demo Modes

The client provides several demo modes:

  1. File Demo (--demo file): Plays an audio file
  2. Tone Demo (--demo tone): Generates and plays a tone with specified frequency
  3. Volume Demo (--demo volume): Demonstrates volume control
  4. All Demos (--demo all): Runs all demos in sequence

Supported Speaker Operations

The speaker examples support the following operations:

Audio Formats

The speaker examples support the following audio formats:

Troubleshooting

  1. Speaker Not Detected: Ensure the speaker is properly connected and recognized by the system:
    # List audio output devices
    aplay -l
    
  2. No Sound: Check if the volume is muted or too low:
    # Check and adjust volume
    amixer sset 'Master' 80%
    
  3. Permission Issues: Some systems may require additional permissions for audio access:
    # Add user to audio group
    sudo usermod -a -G audio $USER
    
  4. PyAudio Installation Issues: If you have trouble installing PyAudio, try:
    # Install dependencies
    sudo apt-get install portaudio19-dev python3-pyaudio
       
    # Then install PyAudio
    pip install pyaudio
    
  5. Audio Quality Issues: If you experience poor audio quality, try using a different audio output device or format.

  6. Connection Issues: Ensure the server is running and accessible from the client’s network.

Example Use Cases

  1. Remote Audio Player: Control audio playback on a Raspberry Pi from another device
  2. Notification System: Play alert sounds or notifications remotely
  3. Multi-Room Audio: Create a distributed audio system with multiple Raspberry Pis
  4. Text-to-Speech Output: Combine with a text-to-speech service to create voice announcements
  5. Interactive Projects: Add audio feedback to interactive projects

UnitAPI Docker Example: Remote Speaker Agent

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.

Overview

This Docker Compose setup creates two containers:

  1. speaker-server: A container that runs virtual speakers and exposes them through the UnitAPI protocol.
  2. speaker-client: A container that connects to the speaker server, installs the UnitAPI speaker agent using SSH, and provides a client interface to control the speakers.

This setup simulates a real-world scenario where you have a remote PC with speakers that you want to control from another PC.

Prerequisites

Directory Structure

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

How It Works

  1. The speaker-server container creates virtual speakers and exposes them through the UnitAPI protocol.
  2. The speaker-client container connects to the server via SSH and installs the UnitAPI speaker agent.
  3. The client then connects to the server’s UnitAPI interface to control the virtual speakers.

This simulates the process of installing the UnitAPI speaker agent on a remote PC and controlling its speakers.

Usage

Starting the Containers

# Navigate to the docker directory
cd examples/docker

# Start the containers
docker-compose up -d

# View the logs
docker-compose logs -f

Accessing the Client Container

# 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

Accessing the Server Container

# 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

Stopping the Containers

# Stop the containers
docker-compose down

Customization

You can customize the setup by modifying the following files:

Environment Variables

The Docker Compose setup supports the following environment variables:

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

Testing the Setup

Once the containers are running, you can test the setup by:

  1. Listing the available speakers:
    docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --list
    
  2. Testing all speakers:
    docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --test
    
  3. Testing a specific speaker:
    docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --device virtual_speaker_1
    
  4. Monitoring the speakers:
    docker exec -it unitapi-speaker-client python /opt/unitapi/client.py --host 172.28.1.2 --monitor --interval 30
    

Troubleshooting

If you encounter issues with the setup, check the following:

  1. Make sure the containers are running:
    docker-compose ps
    
  2. Check the container logs:
    docker-compose logs -f
    
  3. Verify the network connectivity between the containers:
    docker exec -it unitapi-speaker-client ping 172.28.1.2
    
  4. Check if the SSH server is running on the server container:
    docker exec -it unitapi-speaker-server service ssh status
    
  5. Verify the UnitAPI server is running on the server container:
    docker exec -it unitapi-speaker-server ps aux | grep unitapi
    

Extending the Example

You can extend this example to include more features:

  1. Add more virtual speakers by changing the VIRTUAL_SPEAKERS environment variable.
  2. Implement a web interface for controlling the speakers.
  3. Add support for playing audio files from the client to the server.
  4. Integrate with other UnitAPI devices like microphones or cameras.

Conclusion

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