Documentation
¶
Overview ¶
Package quote0 provides a Go 1.18+ SDK for Quote/0 e-ink display devices.
Quote/0 is a Wi-Fi enabled e-paper display with a 296×152 pixel screen that receives content updates via REST API. The device maintains displayed content without power (bistable e-ink) and supports both text-based layouts and arbitrary image rendering. See https://dot.mindreset.tech for device specifications and documentation.
Features
- Bearer token authentication
- Optional default device ID with per-request override
- 1 QPS rate limiting (pluggable, context aware)
- Robust error handling for JSON and plain-text (Chinese) responses
- No third-party dependencies (stdlib only)
Official API Documentation:
Index ¶
- Constants
- Variables
- func Bool(v bool) *bool
- func Int(v int) *int
- func IsAuthError(err error) bool
- func IsRateLimitError(err error) bool
- type APIError
- type APIResponse
- type BorderColor
- type Client
- func (c *Client) GetDefaultDeviceID() string
- func (c *Client) SendImage(ctx context.Context, payload ImageRequest) (*APIResponse, error)
- func (c *Client) SendImageBytes(ctx context.Context, png []byte, meta ImageRequest) (*APIResponse, error)
- func (c *Client) SendImageFile(ctx context.Context, path string, meta ImageRequest) (*APIResponse, error)
- func (c *Client) SendImageSimple(base64PNG string) (*APIResponse, error)
- func (c *Client) SendImageToDevice(ctx context.Context, deviceID string, payload ImageRequest) (*APIResponse, error)
- func (c *Client) SendText(ctx context.Context, payload TextRequest) (*APIResponse, error)
- func (c *Client) SendTextSimple(title, message string, signature ...string) (*APIResponse, error)
- func (c *Client) SendTextToDevice(ctx context.Context, deviceID string, payload TextRequest) (*APIResponse, error)
- func (c *Client) SetDefaultDeviceID(deviceID string)
- type ClientOption
- type DitherKernel
- type DitherType
- type ImageRequest
- type RateLimiter
- type RateLimiterFunc
- type TextRequest
Constants ¶
const ( // DefaultBaseURL is the default API host. Endpoints are under /api/open/*. // This matches the official curl examples. DefaultBaseURL = "https://dot.mindreset.tech" )
Variables ¶
var ( // ErrDeviceIDMissing indicates deviceId is required. ErrDeviceIDMissing = errors.New("quote0: deviceId is required") // ErrImagePayloadMissing indicates image payload is required. ErrImagePayloadMissing = errors.New("quote0: image payload is required") // ErrTitleMissing indicates title is required. ErrTitleMissing = errors.New("quote0: title is required") // ErrMessageMissing indicates message is required. ErrMessageMissing = errors.New("quote0: message is required") )
Functions ¶
func IsAuthError ¶
IsAuthError returns true if err is an APIError with HTTP status 401 or 403 (authentication/authorization failure).
func IsRateLimitError ¶
IsRateLimitError returns true if err is an APIError with HTTP status 429 (Too Many Requests).
Types ¶
type APIError ¶
type APIError struct {
StatusCode int
// Code is a normalized string representation of server error code when present (e.g. "429").
Code string
// Message is a human-readable message from the server or synthesized from body.
Message string
// RawBody keeps the original payload for debugging.
RawBody []byte
}
APIError captures non-2xx responses. The service may return JSON or plain text (e.g. Chinese).
type APIResponse ¶
type APIResponse struct {
// Code carries the numeric status returned by the Quote/0 API (0 on success).
Code int `json:"code"`
// Message is the string message provided by the service (e.g., "ok" or reason text).
Message string `json:"message"`
// Result contains the raw JSON payload (varies per endpoint; caller can unmarshal).
Result json.RawMessage `json:"result"`
// StatusCode keeps the HTTP status code observed for the request.
StatusCode int `json:"-"`
// RawBody contains the exact response bytes for troubleshooting or custom parsing.
RawBody []byte `json:"-"`
}
APIResponse reflects a typical JSON envelope from the service. Some responses may be plain text; in those cases, Message/StatusCode/RawBody are set.
type BorderColor ¶
type BorderColor int
BorderColor controls the screen edge color on the Quote/0 display.
const ( // BorderWhite renders a white border around the display (default). BorderWhite BorderColor = 0 // BorderBlack renders a black border around the display. BorderBlack BorderColor = 1 )
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client exposes the Quote/0 APIs with proper authentication and rate limiting.
func NewClient ¶
func NewClient(apiKey string, opts ...ClientOption) (*Client, error)
NewClient builds a client. apiKey is required (format: dot_app_xxx).
func (*Client) GetDefaultDeviceID ¶
GetDefaultDeviceID returns the current default device ID.
func (*Client) SendImage ¶
func (c *Client) SendImage(ctx context.Context, payload ImageRequest) (*APIResponse, error)
SendImage uploads a base64-encoded image to the device. If DeviceID is empty, the client's default device is used.
func (*Client) SendImageBytes ¶
func (c *Client) SendImageBytes(ctx context.Context, png []byte, meta ImageRequest) (*APIResponse, error)
SendImageBytes is a convenience that accepts raw PNG bytes and performs base64 encoding internally.
func (*Client) SendImageFile ¶
func (c *Client) SendImageFile(ctx context.Context, path string, meta ImageRequest) (*APIResponse, error)
SendImageFile is a convenience that accepts a PNG file path and performs base64 encoding internally.
func (*Client) SendImageSimple ¶
func (c *Client) SendImageSimple(base64PNG string) (*APIResponse, error)
SendImageSimple sends an image with default device and immediate refresh using Background context.
func (*Client) SendImageToDevice ¶
func (c *Client) SendImageToDevice(ctx context.Context, deviceID string, payload ImageRequest) (*APIResponse, error)
SendImageToDevice is a convenience to target a specific device.
func (*Client) SendText ¶
func (c *Client) SendText(ctx context.Context, payload TextRequest) (*APIResponse, error)
SendText sends text content. If DeviceID is empty, the client's default device is used.
func (*Client) SendTextSimple ¶
func (c *Client) SendTextSimple(title, message string, signature ...string) (*APIResponse, error)
SendTextSimple is a convenience helper using Background context and immediate refresh. Title and message are optional. Signature is variadic; when omitted, no signature is sent.
func (*Client) SendTextToDevice ¶
func (c *Client) SendTextToDevice(ctx context.Context, deviceID string, payload TextRequest) (*APIResponse, error)
SendTextToDevice is a convenience to target a specific device.
func (*Client) SetDefaultDeviceID ¶
SetDefaultDeviceID updates the default device ID in a thread-safe manner.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption mutates the client during construction.
func WithBaseURL ¶
func WithBaseURL(baseURL string) ClientOption
WithBaseURL overrides the API host (useful for staging/tests). No trailing slash required.
func WithDebug ¶
func WithDebug(debug bool) ClientOption
WithDebug enables debug mode which logs request details (method, URL, headers, body) to stderr. Useful for debugging and verifying SDK behavior.
func WithDefaultDeviceID ¶
func WithDefaultDeviceID(deviceID string) ClientOption
WithDefaultDeviceID sets a default device serial number used when request omits deviceId.
func WithHTTPClient ¶
func WithHTTPClient(hc *http.Client) ClientOption
WithHTTPClient installs a custom http.Client.
func WithRateLimiter ¶
func WithRateLimiter(l RateLimiter) ClientOption
WithRateLimiter replaces the default limiter. Pass nil to disable (not recommended).
func WithUserAgent ¶
func WithUserAgent(ua string) ClientOption
WithUserAgent sets a custom User-Agent string. Pass an empty string to send an empty User-Agent header (not recommended). If not called, the client uses a default SDK User-Agent.
type DitherKernel ¶
type DitherKernel string
DitherKernel enumerates supported dithering kernels/algorithms.
IMPORTANT: DitherKernel is only effective when DitherType is set to DIFFUSION. When DitherType is ORDERED or NONE, the kernel parameter is ignored by the server.
When DitherType is DIFFUSION, these kernels control how quantization error is spread: - KernelFloydSteinberg: Classic 3x3 diffusion (default). Balanced detail and smoothness. - KernelAtkinson: Lighter diffusion footprint; preserves micro-detail and text; slightly lighter images. - KernelBurkes: Row-oriented diffusion similar to Stucki but lighter weights; sharp edges, fine detail. - KernelSierra2: Sierra-2 variant; smooth gradients with moderate grain; balanced look. - KernelStucki: Larger footprint; strong contrast and crisp edges; can introduce more visible grain. - KernelJarvisJudiceNinke: Large footprint; very smooth gradients, may blur fine details slightly. - KernelDiffusionRow: Directional diffusion along rows; preserves horizontal detail; may create row texture. - KernelDiffusionColumn: Directional diffusion along columns; preserves vertical detail; may create column texture. - KernelDiffusion2D: More isotropic spread across 2D neighborhood; balances artifacts across directions. - KernelThreshold: Listed for completeness, but primarily used with ORDERED dither type.
const ( // KernelThreshold applies ordered dithering threshold matrix; no error diffusion; strong halftone look. KernelThreshold DitherKernel = "THRESHOLD" // KernelAtkinson uses compact diffusion pattern; good for text and small features; lighter tones. KernelAtkinson DitherKernel = "ATKINSON" // KernelBurkes applies diffusion with emphasis on immediate neighbors along the row; sharp, detailed output. KernelBurkes DitherKernel = "BURKES" // KernelFloydSteinberg is the default, classic diffusion; natural gradients and balanced detail/grain. KernelFloydSteinberg DitherKernel = "FLOYD_STEINBERG" // KernelSierra2 applies Sierra-2 diffusion; smooth gradients; moderate granularity. KernelSierra2 DitherKernel = "SIERRA2" // KernelStucki uses larger kernel; increases perceived sharpness; can be grainier. KernelStucki DitherKernel = "STUCKI" // KernelJarvisJudiceNinke produces very smooth gradients due to large kernel; may soften fine details. KernelJarvisJudiceNinke DitherKernel = "JARVIS_JUDICE_NINKE" // KernelDiffusionRow applies directional diffusion horizontally; preserves horizontal features. KernelDiffusionRow DitherKernel = "DIFFUSION_ROW" // KernelDiffusionColumn applies directional diffusion vertically; preserves vertical features. KernelDiffusionColumn DitherKernel = "DIFFUSION_COLUMN" // KernelDiffusion2D spreads error across a 2D neighborhood; balances directional artifacts. KernelDiffusion2D DitherKernel = "DIFFUSION_2D" )
type DitherType ¶
type DitherType string
DitherType enumerates server-accepted dithering modes.
Server behavior (per official docs):
- If ditherType is omitted, the default is error diffusion using the Floyd-Steinberg kernel.
- DIFFUSION: Error diffusion algorithms that distribute quantization errors to neighbors. When using DIFFUSION, you can specify a DitherKernel to control the error distribution pattern.
- ORDERED: Fixed periodic threshold matrix producing uniform dot patterns with regular grids.
- NONE: Disables dithering entirely; recommended for text-based images for sharper rendering.
Note: DitherKernel is only effective when DitherType is DIFFUSION. For ORDERED or NONE, the kernel parameter is ignored by the server.
const ( // DitherNone disables dithering entirely; pixels are binarized by a simple threshold. // Suitable for high-contrast line art or when you require crisp edges without added grain, // but gradients will posterize. DitherNone DitherType = "NONE" // DitherDiffusion enables error-diffusion dithering. Each pixel's quantization error // is distributed to neighbors based on a selected kernel, producing smooth tonal // transitions with natural-looking noise. Good general-purpose choice for photos/text. DitherDiffusion DitherType = "DIFFUSION" // DitherOrdered enables ordered dithering via a threshold matrix (Bayer-like). This // yields a regular halftone pattern that preserves uniform regions and text edges well, // but can reveal grid artifacts in smooth gradients. DitherOrdered DitherType = "ORDERED" )
type ImageRequest ¶
type ImageRequest struct {
// RefreshNow toggles an immediate display refresh for the targeted screen.
RefreshNow *bool `json:"refreshNow,omitempty"`
// DeviceID is the Quote/0 serial number (hexadecimal string). Leave empty to use the client's default device.
DeviceID string `json:"deviceId"`
// Image is a base64-encoded 296x152px PNG payload as required by the server.
// You normally do not need to set this directly when using ImageBytes or ImagePath.
Image string `json:"image"`
// ImageBytes allows providing raw 296x152px PNG bytes; the SDK will base64-encode internally.
ImageBytes []byte `json:"-"`
// ImagePath allows providing a file path to a 296x152px PNG; the SDK will read and base64-encode internally.
ImagePath string `json:"-"`
// Link is an optional URL opened inside the Quote/0 companion app.
Link string `json:"link,omitempty"`
// Border selects the screen edge color. Use BorderWhite (default) or BorderBlack.
Border BorderColor `json:"border,omitempty"`
// DitherType selects the server-side dithering strategy for tone reproduction.
DitherType DitherType `json:"ditherType,omitempty"`
// DitherKernel narrows the algorithm used when DitherType=DIFFUSION or ORDERED.
DitherKernel DitherKernel `json:"ditherKernel,omitempty"`
}
ImageRequest matches the /api/open/image payload.
type RateLimiter ¶
RateLimiter gates outgoing API calls so we stay under the documented 1 QPS. Implementations must honor context cancellation so callers can abort pending calls cleanly.
func NewFixedIntervalLimiter ¶
func NewFixedIntervalLimiter(interval time.Duration) RateLimiter
NewFixedIntervalLimiter creates a simple, concurrency-safe limiter that enforces a minimum interval between requests. It is intentionally lightweight (mutex+timer) so it can run inside tiny IoT gateways or embedded controllers without extra deps. Use this for the official 1 QPS policy by passing time.Second, or customize as needed.
type RateLimiterFunc ¶
RateLimiterFunc adapts a function into a RateLimiter.
type TextRequest ¶
type TextRequest struct {
// RefreshNow toggles an immediate refresh on the targeted Quote/0 display. Optional.
RefreshNow *bool `json:"refreshNow,omitempty"`
// DeviceID is the Quote/0 serial number (hexadecimal string). Required. Leave empty to use the client's default.
DeviceID string `json:"deviceId"`
// Title displays on the first line. Optional.
Title string `json:"title,omitempty"`
// Message displays on the next three lines. Optional.
Message string `json:"message,omitempty"`
// Signature displays fixed at the bottom-right corner. Optional.
Signature string `json:"signature,omitempty"`
// Icon is a base64-encoded 40x40px PNG shown at the bottom-left corner. Optional.
Icon string `json:"icon,omitempty"`
// Link is an optional URL that the Quote/0 companion app can open when interacting with the device.
Link string `json:"link,omitempty"`
}
TextRequest matches the /api/open/text payload. Only DeviceID is required; all other fields are optional.
Display Layout: The Quote/0 screen has a fixed layout (296x152 pixels):
- Title: displays on the first line
- Message: displays on the next three lines
- Icon: 40x40px at the bottom-left corner
- Signature: fixed at the bottom-right corner
If any field is omitted, that area remains blank. The layout does not reflow or adjust responsively.