gRPC for the PANOSETI project.
Project description
PANOSETI gRPC Services
This repository contains the microservice architecture for the PANOSETI observatory. It provides gRPC interfaces for real-time data access, observatory control, and general telemetry logging. See here for the main software repo.
Service Directory
Each service operates independently. Click the links below for detailed API documentation and configuration guides.
| Service | Description | Status | Documentation |
|---|---|---|---|
| DAQ Data | Streams real-time science data directly from Hashpipe. | 🟢 Production | Read Docs |
| DAQ Control | Manages Hashpipe lifecycle on DAQ nodes (start/stop/status). | 🟡 Beta | Read Docs |
| U-blox Control | Controls and configures GNSS chips (F9T/F9P). | 🟢 Production | Read Docs |
| Telemetry | Collects metadata from remote Linux machines. | 🟡 Beta | Read Docs |
📜 Changelog
Keep track of the latest changes, modernization efforts, and breaking changes in our Changelog.
📦 Installation (Client Mode)
If you only need to write scripts to control the observatory or analyze data, install the package from PyPI:
pip install panoseti-grpc
Example Usage:
from panoseti_grpc.telemetry.client import TelemetryClient
# Connect to a running Telemetry Service
client = TelemetryClient("localhost", 50051)
# Upload metadata
client.log_flexible("example", "weather-01", {"status": "Online", "is-raining": True})
🛠️ Development & Contribution
Environment Setup
If you are deploying the servers on the head node or contributing to the codebase, we recommend installing miniconda (link), then following these steps to setup your environment:
# 0. Clone this repo and go to the repo root
git clone https://github.com/panoseti/panoseti_grpc.git
cd panoseti_grpc
# 1. Create the grpc-py314 conda environment
conda create -n grpc-py314 python=3.14
conda activate grpc-py314
# 2. Install in editable mode with development dependencies
pip install -e ".[dev]"
🚦 Unified Server
All three active services (daq_data, daq_control, telemetry) can run on a single port under a unified process. gRPC routes RPCs by proto package name automatically — no collision between services.
Quick Start
# All services on one port (default: 50051)
panoseti-server
# DAQ node: daq_data + daq_control only
panoseti-server --profile daq_node
# Head node: telemetry only
panoseti-server --profile headnode
# Custom config file
panoseti-server --config /etc/panoseti/server.toml
# List all registered services
panoseti-server --list-services
Deployment Profiles
| Profile | Services | Machine |
|---|---|---|
default |
telemetry + daq_data + daq_control | Single-machine dev / test |
daq_node |
daq_data + daq_control | Each DAQ compute node |
headnode |
telemetry | Observatory head node |
On DAQ nodes (telemetry = false), services configured with grpc_logging = true automatically forward logs to the head node's telemetry endpoint via the HEADNODE_IP / HEADNODE_GRPC_PORT environment variables.
Config File Structure
Bundled profiles live in src/panoseti_grpc/config/. A custom server.toml follows this structure:
[server]
port = 50051
shutdown_grace_period = 5.0
log_dir = "/var/log/panoseti"
grpc_logging = true
[server.services]
telemetry = true
daq_data = true
daq_control = true
[telemetry]
redis_host = "localhost"
redis_port = 6379
[daq_data]
# ... DaqDataServerConfig fields ...
[daq_control]
log_dir = "/var/log/panoseti"
🧪 Testing
We use a comprehensive CI pipeline (GitHub Actions) to verify every commit. You can—and should—run these same tests locally before pushing code.
Unified QA Runner (Recommended)
The most efficient way to run quality checks and tests is via the unified QA runner:
# Run all linters and test suites
python tests/qa.py all
# Run specific tasks
python tests/qa.py lint
python tests/qa.py telemetry
Run CI Tests Locally via Bash Scripts
Alternatively, you can use the individual scripts in scripts/run-ci-tests/.
Each service has an associated script which builds the Docker containers and runs the appropriate test suites.
Examples:
# Run DAQ Data Service tests
./scripts/run-ci-tests/run-daq-data-ci-test.sh
# Run U-blox Control Service tests
./scripts/run-ci-tests/run-ublox-control-ci-test.sh
🚀 Adding New Services
The PANOSETI gRPC architecture is designed to be extensible. New services slot into the unified server without modifying PanosetiServer itself — only server.py registration and config additions are needed.
0. Branching Strategy
Always create a new feature branch off the development branch:
git checkout dev
git checkout -b feature/daq-control-service
1. Define the Interface (.proto)
Create a new Protocol Buffer definition file in the protos/ directory. This defines the contract between your client and server.
- File:
protos/daq_control.proto - Example:
syntax = "proto3";
package panoseti.daq_control;
service DaqControl {
rpc SetHighVoltage (VoltageRequest) returns (StatusResponse) {}
}
message VoltageRequest { float voltage = 1; }
message StatusResponse { bool success = 1; }
2. Compile the Protos
Run the compilation script to generate the Python gRPC code.
python scripts/compile_protos.py
This will automatically generate two files in src/panoseti_grpc/generated/:
daq_control_pb2.py(Message definitions)daq_control_pb2_grpc.py(Client/Server stubs)
3. Create the Service Module
Create a new directory for your service source code. You must include an __init__.py file for Python to recognize it as a package.
mkdir -p src/panoseti_grpc/daq_control
touch src/panoseti_grpc/daq_control/__init__.py
4. Implement Client & Server
Develop your application logic. You can now import your generated protobuf code using the package path.
Example src/panoseti_grpc/daq_control/server.py:
import grpc
from panoseti_grpc.generated import daq_control_pb2, daq_control_pb2_grpc
class DaqControlServicer(daq_control_pb2_grpc.DaqControlServicer):
def SetHighVoltage(self, request, context):
print(f"Setting voltage to {request.voltage}")
return daq_control_pb2.StatusResponse(success=True)
5. Register with the Unified Server
To make the service available via panoseti-server, add it to src/panoseti_grpc/server.py:
- Write
async def _make_<name>_servicer(cfg, shutdown_event)that returns(servicer, [post_start_coros]) - Add
<name>: NewServiceConfig = Field(default_factory=NewServiceConfig)toPanosetiServerConfig - Add
<name>: bool = FalsetoServiceToggles - Call
ServiceRegistry.register(ServiceDescriptor("<name>", ...))at module level - Add a
[<name>]section to the relevantserver*.tomlprofile files
6. Add CI Tests
Finally, ensure your new service is robust by adding a test suite.
- Create a test directory:
tests/<name>/ - Add a BuildKit stage to the root
Dockerfile.cifor your test environment. - Add a runner script in
scripts/run-ci-tests/run-<name>-ci-test.sh. - Create unit and integration tests with pytest.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file panoseti_grpc-0.4.8.tar.gz.
File metadata
- Download URL: panoseti_grpc-0.4.8.tar.gz
- Upload date:
- Size: 16.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05775fb57d70f5fe2b035acd14d5ca11a2fbbfe753375971aebaba91db785a79
|
|
| MD5 |
c4f422ffe63ba5d608138054c25e9322
|
|
| BLAKE2b-256 |
f30d6a2c642a59b21b744b2d3cf50b580f3879fbefc729c35744ddc180faf29d
|
File details
Details for the file panoseti_grpc-0.4.8-py3-none-any.whl.
File metadata
- Download URL: panoseti_grpc-0.4.8-py3-none-any.whl
- Upload date:
- Size: 16.3 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b66b517b78d449ca3826b00f427e6617222f7f1996d8d95484594dc464c0d18
|
|
| MD5 |
f787015099a1579abe742fe76c27762c
|
|
| BLAKE2b-256 |
a9fa38e141eeea99c7739761d83e05c9348bf3b6b418adb5f2fb414e87323175
|