Skip to content

Commit 0fa4a05

Browse files
feat: Initial commit of Sony Camera Manager
- Added GitHub Actions workflow for running tests on push and pull requests. - Created .gitignore to exclude unnecessary files from version control. - Added CHANGELOG.md to document project changes. - Included MIT License for open-source distribution. - Wrote README.md with project overview, installation instructions, and usage examples. - Implemented example scripts for camera connection, exposure control, and live view streaming using OpenCV. - Established project structure with pyproject.toml for dependencies and build configuration. - Created SonyCameraClient for camera control, including methods for exposure, focus, and live view. - Developed LiveviewStream class for parsing live view binary streams. - Added exception handling for camera connection and protocol errors. - Defined models for camera status, exposure modes, and actions. - Implemented transport layer for JSON-RPC communication with the camera. - Created tests for client functionality and camera interactions.
0 parents  commit 0fa4a05

19 files changed

Lines changed: 1111 additions & 0 deletions

.github/workflows/tests.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.11"]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
cache: 'pip'
24+
25+
- name: Install dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install -e .[dev]
29+
30+
- name: Run tests with pytest
31+
run: |
32+
pytest tests/

.gitignore

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
bin/
11+
build/
12+
develop-eggs/
13+
dist/
14+
eggs/
15+
lib/
16+
lib64/
17+
parts/
18+
sdist/
19+
var/
20+
wheels/
21+
*.egg-info/
22+
.installed.cfg
23+
*.egg
24+
25+
# PyInstaller
26+
# Usually these files are written by a python script from a template
27+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
28+
*.manifest
29+
*.spec
30+
31+
# Installer logs
32+
pip-log.txt
33+
pip-delete-this-directory.txt
34+
35+
# Unit test / coverage reports
36+
htmlcov/
37+
.tox/
38+
.coverage
39+
.coverage.*
40+
.cache
41+
nosetests.xml
42+
coverage.xml
43+
*.cover
44+
.hypothesis/
45+
.pytest_cache/
46+
47+
# Translations
48+
*.mo
49+
*.pot
50+
51+
# Django stuff:
52+
*.log
53+
local_settings.py
54+
55+
# Flask stuff:
56+
instance/
57+
.webassets-cache
58+
59+
# Scrapy stuff:
60+
.scrapy
61+
62+
# Sphinx documentation
63+
docs/_build/
64+
65+
# PyBuilder
66+
target/
67+
68+
# Jupyter Notebook
69+
.ipynb_checkpoints
70+
71+
# pyenv
72+
.python-version
73+
74+
# celery beat schedule file
75+
celerybeat-schedule
76+
77+
# SageMath parsed files
78+
*.sage.py
79+
80+
# dotenv
81+
.env
82+
.venv
83+
env/
84+
venv/
85+
ENV/
86+
87+
# Spyder project settings
88+
.spyderproject
89+
.spyproject
90+
91+
# Rope project settings
92+
.ropeproject
93+
94+
# mkdocs documentation
95+
/site
96+
97+
# mypy
98+
.mypy_cache/
99+
100+
# OS generated files
101+
.DS_Store
102+
Thumbs.db

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.1.0] - 2026-01-21
9+
10+
### Added
11+
- Initial release of `sony-camera-manager`.
12+
- `SonyCameraClient` for controlling Sony cameras via JSON-RPC.
13+
- `LiveviewStream` for parsing MJPEG streams.
14+
- SSDP discovery for finding cameras on the network.
15+
- Production-ready source layout.
16+
- Type hints for all public methods.
17+
- Custom exception hierarchy.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Sezer
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Sony Sony Camera Manager (Python)
2+
3+
A comprehensive, high-level Python client for controlling Sony cameras (like the ZV-E10, A7RIII, etc.) via the legacy **Camera Remote API** (JSON-RPC over HTTP).
4+
5+
## 1) Overview
6+
This package is designed to be the "best ever" implementation for Sony's legacy API, focusing on:
7+
- **Capability-First Architecture**: Always probe what the camera supports before calling.
8+
- **Dynamic Method Surface**: Use `cam.do("methodName", ...)` for any method not explicitly wrapped.
9+
- **Robust Liveview**: High-performance binary stream parser for JPEG frames.
10+
- **Comprehensive Actions**: Full catalog of Sony API methods as constants.
11+
12+
## 2) Key Features
13+
- **Auto-Discovery**: Discover cameras on the network using SSDP.
14+
- **Full Exposure Control**: Aperture, Shutter Speed, ISO, Exposure Compensation, etc.
15+
- **Advanced Focus**: Focus modes, Touch AF position, Tracking Focus.
16+
- **Live View**: Frame-by-frame JPEG extraction from the binary stream.
17+
- **Event Monitoring**: Long-polling support to track battery, status, and settings changes.
18+
19+
## 3) Installation
20+
```bash
21+
pip install sony-camera-manager
22+
# For developers
23+
pip install sony-camera-manager[dev]
24+
```
25+
26+
## 4) Usage
27+
28+
### 4.1 Discovery & Initialization
29+
```python
30+
from sony_camera_manager import SonyCameraClient
31+
32+
# Auto-discovery
33+
host = SonyCameraClient.discover()
34+
if not host:
35+
host = "192.168.122.1" # Fallback
36+
37+
cam = SonyCameraClient(host=host)
38+
```
39+
40+
### 4.2 Probing Capabilities (The Sony Way)
41+
Sony cameras change their available APIs based on their current mode (e.g., Movie vs Still).
42+
```python
43+
# Check what's supported by the hardware
44+
print(cam.get_api_list())
45+
46+
# Check what's available in the current mode
47+
print(cam.get_available_api_list())
48+
49+
# Generic capability helpers
50+
supported_iso = cam.get_supported("IsoSpeedRate")
51+
available_f_numbers = cam.get_available("FNumber")
52+
```
53+
54+
### 4.3 High-Level API Examples
55+
```python
56+
from sony_camera_manager.models import ExposureMode
57+
58+
# Set Manual Mode
59+
cam.set_shoot_mode(ExposureMode.MANUAL)
60+
61+
# Adjust Exposure
62+
cam.set_f_number("5.6")
63+
cam.set_shutter_speed("1/100")
64+
cam.set_iso_speed_rate("400")
65+
66+
# Focus tracking
67+
cam.act_tracking_focus(0.5, 0.5) # Center
68+
69+
# Take a photo and wait for result
70+
image_urls = cam.await_take_picture()
71+
```
72+
73+
### 4.4 Liveview Stream (OpenCV)
74+
```python
75+
import cv2
76+
import numpy as np
77+
78+
for jpeg in cam.get_liveview_stream():
79+
img = cv2.imdecode(np.frombuffer(jpeg, np.uint8), cv2.IMREAD_COLOR)
80+
cv2.imshow('Sony Liveview', img)
81+
if cv2.waitKey(1) == ord('q'): break
82+
83+
cv2.destroyAllWindows()
84+
cam.stop_liveview()
85+
```
86+
87+
## 5) Package Structure
88+
- `SonyCameraClient`: Main interface for controlling the camera.
89+
- `transport`: Low-level JSON-RPC communication handler (internal).
90+
- `models`: Dataclasses and Enums for Camera state and settings.
91+
- `exceptions`: Custom exception hierarchy (CameraError, ConnectionError, etc.).
92+
93+
## 6) References
94+
- [Sony Camera Remote API Documentation](https://developer.sony.com/develop/cameras/)
95+
- [libsonyapi](https://github.com/petabite/libsonyapi) (Method catalog inspiration)
96+
- [pysony](https://github.com/Bloodevil/sony_camera_api) (Protocol reference)

examples/01_connection.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Simple example showing how to discover and connect to a Sony camera.
3+
"""
4+
from sony_camera_manager import SonyCameraClient
5+
import sys
6+
7+
def main():
8+
print("Searching for Sony cameras on the network...")
9+
host = SonyCameraClient.discover(timeout=5.0)
10+
11+
if not host:
12+
print("No camera discovered automatically.")
13+
host = input("Please enter the camera IP manually (default 192.168.122.1): ") or "192.168.122.1"
14+
else:
15+
print(f"Discovered camera at: {host}")
16+
17+
try:
18+
# Initialize camera
19+
cam = SonyCameraClient(host=host)
20+
21+
# Check basic info
22+
api_version = cam.call("system", "getVersions")["result"][0]
23+
print(f"Connected! API Versions: {api_version}")
24+
25+
# List what we can do right now
26+
available = cam.get_available_api_list()
27+
print(f"Available methods in current mode: {len(available)}")
28+
print(f"Sample available methods: {available[:5]}...")
29+
30+
except Exception as e:
31+
print(f"Error connecting to camera: {e}")
32+
sys.exit(1)
33+
34+
if __name__ == "__main__":
35+
main()

examples/02_exposure_control.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
Example showing how to control exposure settings (Mode, ISO, Aperture, Shutter).
3+
Requires the camera to be in a compatible mode (e.g., Manual or Priority).
4+
"""
5+
from sony_camera_manager import SonyCameraClient
6+
from sony_camera_manager.models import ExposureMode
7+
import time
8+
9+
def main():
10+
host = SonyCameraClient.discover() or "192.168.122.1"
11+
cam = SonyCameraClient(host=host)
12+
13+
print("--- Camera Configuration ---")
14+
15+
# 1. Switch to Manual Mode if possible
16+
try:
17+
print("Setting shoot mode to Manual...")
18+
cam.set_shoot_mode(ExposureMode.MANUAL)
19+
time.sleep(1) # Give camera time to switch
20+
except Exception as e:
21+
print(f"Could not set Manual mode: {e}")
22+
23+
# 2. Query available ranges
24+
try:
25+
avail_iso = cam.get_available("IsoSpeedRate")
26+
print(f"Available ISO values: {avail_iso}")
27+
28+
avail_f = cam.get_available("FNumber")
29+
print(f"Available F-Numbers: {avail_f}")
30+
except Exception as e:
31+
print(f"Error querying availability: {e}")
32+
33+
# 3. Set specific values
34+
try:
35+
print("Setting ISO to 400...")
36+
cam.set_iso_speed_rate("400")
37+
38+
# Note: Values must match exactly what get_available returned
39+
if "5.6" in str(avail_f):
40+
print("Setting Aperture to 5.6...")
41+
cam.set_f_number("5.6")
42+
43+
print("Current Shutter Speed:", cam.get_shutter_speed())
44+
except Exception as e:
45+
print(f"Error setting values: {e}")
46+
47+
if __name__ == "__main__":
48+
main()

0 commit comments

Comments
 (0)