@nodify_at/picamera.js
Version:
High-performance, low-CPU camera capture module using picamera for Raspberry Pi
181 lines (155 loc) • 3.94 kB
text/typescript
// types.ts - Simple types that match C++ expectations directly
// Control enums
export const enum ExposureMode {
NORMAL = 0,
SHORT = 1,
LONG = 2,
CUSTOM = 3
}
export const enum AfMode {
MANUAL = 0,
AUTO = 1,
CONTINUOUS = 2
}
export const enum AfTrigger {
START = 0,
CANCEL = 1
}
export const enum AwbMode {
AUTO = 0,
INCANDESCENT = 1,
TUNGSTEN = 2,
FLUORESCENT = 3,
INDOOR = 4,
DAYLIGHT = 5,
CLOUDY = 6,
CUSTOM = 7
}
// Core types - simple and direct
export interface StreamConfig {
type: 'jpeg' | 'rgb' | 'raw'
width?: number
height?: number
}
export interface Controls {
exposureMode?: ExposureMode
exposureTime?: number
analogueGain?: number
afMode?: AfMode
afTrigger?: AfTrigger
lensPosition?: number
awbMode?: AwbMode
colourGains?: [number, number] // [red, blue] - matches C++ expectation
brightness?: number
contrast?: number
saturation?: number
sharpness?: number
targetFps?: number
jpegQuality?: number
}
export interface CameraConfig {
rawStream?: { width?: number; height?: number }
streams: StreamConfig[]
controls?: Controls
jpegEncoderQueueSize?: number
}
// Frame data
export interface FrameData {
data: Buffer
timestamp: bigint
sequence: number
}
export interface FrameEvent {
type: 'frame'
stream: 'jpeg' | 'rgb' | 'raw'
frame: FrameData
}
export interface ErrorEvent {
type: 'error'
error: string
}
export type CameraEvent = FrameEvent | ErrorEvent
// Capabilities
export interface CapabilityRange {
min: number
max: number
default: number
}
export interface CameraCapabilities {
exposureTime?: CapabilityRange
analogueGain?: CapabilityRange
lensPosition?: CapabilityRange
afModes: readonly string[]
awbModes: readonly string[]
}
export interface SensorInfo {
width: number
height: number
model: string
}
// Dimensions helper
export interface Dimensions {
width: number
height: number
}
// Native addon interface
export interface Camera {
start(): boolean
stop(): void
setControls(controls: Controls): boolean
getControls(): Controls
getCapabilities(): CameraCapabilities
getSensorInfo(): SensorInfo
on(event: string, callback: (event: CameraEvent) => void): void
}
export interface CameraConstructor {
new (config: CameraConfig): Camera
}
export interface NativeAddon {
Camera: CameraConstructor
controls: {
ExposureMode: typeof ExposureMode
AfMode: typeof AfMode
AfTrigger: typeof AfTrigger
AwbMode: typeof AwbMode
}
}
// Error handling
export const ErrorCodes = {
ALREADY_RUNNING: 'ALREADY_RUNNING',
START_FAILED: 'START_FAILED',
NOT_INITIALIZED: 'NOT_INITIALIZED',
INVALID_DIMENSION: 'INVALID_DIMENSION',
OUT_OF_RANGE: 'OUT_OF_RANGE',
INVALID_EXPOSURE: 'INVALID_EXPOSURE',
INVALID_GAIN: 'INVALID_GAIN',
NO_STREAMS: 'NO_STREAMS',
} as const
export type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes]
export class CameraError extends Error {
constructor(message: string, public readonly code?: ErrorCode) {
super(message)
this.name = 'CameraError'
}
}
// Type guards
export function isFrameEvent(event: CameraEvent): event is FrameEvent {
return event.type === 'frame'
}
export function isErrorEvent(event: CameraEvent): event is ErrorEvent {
return event.type === 'error'
}
// Validation helpers
export function validateDimensions(width: number, height: number): void {
if (width <= 0 || width > 8192) {
throw new CameraError(`Invalid width: ${width} (must be 1-8192)`, ErrorCodes.INVALID_DIMENSION)
}
if (height <= 0 || height > 8192) {
throw new CameraError(`Invalid height: ${height} (must be 1-8192)`, ErrorCodes.INVALID_DIMENSION)
}
}
export function validateRange(value: number, min: number, max: number, name: string): void {
if (value < min || value > max) {
throw new CameraError(`${name} out of range: ${value} (must be ${min}-${max})`, ErrorCodes.OUT_OF_RANGE)
}
}