lplexc

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 25, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package lplexc provides a Go client for lplex, a CAN bus HTTP bridge for NMEA 2000.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Discover

func Discover(ctx context.Context) (string, error)

Discover browses for a _lplex._tcp mDNS service on the local network and returns the URL of the first instance found. It blocks until a service is discovered or the context is cancelled.

A default 3-second timeout is applied if the context has no deadline.

func DiscoverNamed added in v0.3.1

func DiscoverNamed(ctx context.Context, name string) (string, error)

DiscoverNamed browses for a _lplex._tcp mDNS service whose instance name matches the given name (e.g. "inuc1"). This lets you target a specific lplex server when multiple are on the network. Non-matching services are ignored.

A default 3-second timeout is applied if the context has no deadline.

Types

type BackoffConfig added in v0.3.1

type BackoffConfig struct {
	InitialInterval time.Duration
	MaxInterval     time.Duration
	MaxRetries      int // 0 means unlimited
}

BackoffConfig controls exponential backoff for auto-reconnect.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client communicates with an lplex server over HTTP.

func NewClient

func NewClient(baseURL string, opts ...ClientOption) *Client

NewClient creates a new lplex client pointing at the given server URL. Options configure connection pooling, logging, and reconnect behavior.

func (*Client) CreateSession

func (c *Client) CreateSession(ctx context.Context, cfg SessionConfig) (*Session, error)

CreateSession creates or reconnects a buffered session on the server.

func (*Client) DecodedValues added in v0.3.1

func (c *Client) DecodedValues(ctx context.Context, filter *Filter) ([]DecodedDeviceValues, error)

DecodedValues returns a snapshot of last-known values with PGN fields decoded.

func (*Client) Devices

func (c *Client) Devices(ctx context.Context) ([]Device, error)

Devices returns a snapshot of all NMEA 2000 devices discovered by the server.

func (*Client) RequestPGN added in v0.3.1

func (c *Client) RequestPGN(ctx context.Context, pgn uint32, dst uint8) (*Frame, error)

RequestPGN sends an ISO Request (PGN 59904) asking devices to transmit the specified PGN, and waits for the response. dst is the destination address (use 0xFF for broadcast). The server blocks until a matching frame arrives or the timeout expires.

func (*Client) Send

func (c *Client) Send(ctx context.Context, pgn uint32, src, dst, prio uint8, data []byte) error

Send transmits a CAN frame through the server.

func (*Client) Subscribe

func (c *Client) Subscribe(ctx context.Context, filter *Filter) (*Subscription, error)

Subscribe opens an ephemeral SSE stream (GET /events) with the given filter. Returns a Subscription that yields events until closed or the context is cancelled.

func (*Client) SubscribeReconnect added in v0.3.1

func (c *Client) SubscribeReconnect(ctx context.Context, filter *Filter) <-chan Event

SubscribeReconnect opens an auto-reconnecting SSE stream with the given filter. Returns a channel of events that is closed when the context is cancelled. On disconnect, it reconnects with exponential backoff using the client's configured BackoffConfig.

func (*Client) Values added in v0.3.1

func (c *Client) Values(ctx context.Context, filter *Filter) ([]DeviceValues, error)

Values returns a snapshot of last-known values, optionally filtered.

func (*Client) Watch added in v0.3.1

func (c *Client) Watch(ctx context.Context, pgnNumber uint32) (<-chan WatchValue, error)

Watch opens an auto-reconnecting SSE stream filtered to the given PGN and returns a channel of decoded values. The channel is closed when the context is cancelled. Decode errors are silently skipped (logged at debug level).

Example:

ch := client.Watch(ctx, 129025) // Position Rapid Update
for wv := range ch {
    pos := wv.Value.(pgn.PositionRapidUpdate)
    fmt.Printf("lat=%f lon=%f\n", pos.Latitude, pos.Longitude)
}

type ClientOption added in v0.3.1

type ClientOption func(*clientConfig)

ClientOption configures a Client.

func WithBackoff added in v0.3.1

func WithBackoff(b BackoffConfig) ClientOption

WithBackoff configures the reconnection backoff strategy.

func WithHTTPClient added in v0.3.1

func WithHTTPClient(c *http.Client) ClientOption

WithHTTPClient sets a custom http.Client for all requests.

func WithLogger added in v0.3.1

func WithLogger(l *slog.Logger) ClientOption

WithLogger sets a structured logger for the client.

func WithPoolSize added in v0.3.1

func WithPoolSize(n int) ClientOption

WithPoolSize sets the maximum number of idle connections per host.

func WithTransport added in v0.3.1

func WithTransport(t http.RoundTripper) ClientOption

WithTransport sets a custom http.Transport on the default http.Client. This is a convenience for configuring connection pooling parameters.

type DecodedDeviceValues added in v0.3.1

type DecodedDeviceValues struct {
	Name         string            `json:"name"`
	Source       uint8             `json:"src"`
	Manufacturer string            `json:"manufacturer,omitempty"`
	ModelID      string            `json:"model_id,omitempty"`
	Values       []DecodedPGNValue `json:"values"`
}

DecodedDeviceValues groups decoded PGN values by device.

type DecodedPGNValue added in v0.3.1

type DecodedPGNValue struct {
	PGN         uint32 `json:"pgn"`
	Description string `json:"description"`
	Ts          string `json:"ts"`
	Seq         uint64 `json:"seq"`
	Fields      any    `json:"fields"`
}

DecodedPGNValue is a single PGN's last-known value decoded into named fields.

type Device

type Device struct {
	Src              uint8  `json:"src"`
	Name             string `json:"name"`
	Manufacturer     string `json:"manufacturer"`
	ManufacturerCode uint16 `json:"manufacturer_code"`
	DeviceClass      uint8  `json:"device_class"`
	DeviceFunction   uint8  `json:"device_function"`
	DeviceInstance   uint8  `json:"device_instance"`
	UniqueNumber     uint32 `json:"unique_number"`
	ModelID          string `json:"model_id"`
	SoftwareVersion  string `json:"software_version"`
	ModelVersion     string `json:"model_version"`
	ModelSerial      string `json:"model_serial"`
	ProductCode      uint16 `json:"product_code"`
	FirstSeen        string `json:"first_seen"`
	LastSeen         string `json:"last_seen"`
	PacketCount      uint64 `json:"packet_count"`
	ByteCount        uint64 `json:"byte_count"`
}

Device represents an NMEA 2000 device discovered on the bus.

type DeviceValues added in v0.3.1

type DeviceValues struct {
	Name         string     `json:"name"`
	Source       uint8      `json:"src"`
	Manufacturer string     `json:"manufacturer,omitempty"`
	ModelID      string     `json:"model_id,omitempty"`
	Values       []PGNValue `json:"values"`
}

DeviceValues groups PGN values by device.

type Event

type Event struct {
	Frame  *Frame
	Device *Device
}

Event is a message received from an lplex SSE stream. Exactly one of Frame or Device will be non-nil.

type Filter

type Filter struct {
	PGNs          []uint32 `json:"pgn,omitempty"`
	ExcludePGNs   []uint32 `json:"exclude_pgn,omitempty"`
	Manufacturers []string `json:"manufacturer,omitempty"`
	Instances     []uint8  `json:"instance,omitempty"`
	Names         []string `json:"name,omitempty"`
	ExcludeNames  []string `json:"exclude_name,omitempty"`
}

Filter specifies which CAN frames to receive. Categories are AND'd, values within a category are OR'd.

func (*Filter) IsEmpty

func (f *Filter) IsEmpty() bool

IsEmpty returns true if no filter criteria are set.

type Frame

type Frame struct {
	Seq  uint64 `json:"seq"`
	Ts   string `json:"ts"`
	Prio uint8  `json:"prio"`
	PGN  uint32 `json:"pgn"`
	Src  uint8  `json:"src"`
	Dst  uint8  `json:"dst"`
	Data string `json:"data"`
}

Frame represents a single CAN frame received from the lplex server.

type PGNValue added in v0.3.1

type PGNValue struct {
	PGN  uint32 `json:"pgn"`
	Ts   string `json:"ts"`
	Data string `json:"data"`
	Seq  uint64 `json:"seq"`
}

PGNValue is a single PGN's last-known value.

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session is a buffered connection to an lplex server with cursor tracking and automatic reconnect replay.

func (*Session) Ack

func (s *Session) Ack(ctx context.Context, seq uint64) error

Ack advances the cursor for this session to the given sequence number.

func (*Session) Info

func (s *Session) Info() SessionInfo

Info returns the session metadata from the server.

func (*Session) LastAcked

func (s *Session) LastAcked() uint64

LastAcked returns the last sequence number that was successfully acknowledged.

func (*Session) Subscribe

func (s *Session) Subscribe(ctx context.Context) (*Subscription, error)

Subscribe opens the SSE stream for this session (GET /clients/{id}/events). Replays any buffered frames from the cursor, then streams live.

type SessionConfig

type SessionConfig struct {
	ClientID      string
	BufferTimeout string // ISO 8601 duration, e.g. "PT5M"
	Filter        *Filter
	AckInterval   time.Duration // how often to auto-ACK (0 = manual only)
}

SessionConfig configures a buffered client session.

type SessionInfo

type SessionInfo struct {
	ClientID string   `json:"client_id"`
	Seq      uint64   `json:"seq"`
	Cursor   uint64   `json:"cursor"`
	Devices  []Device `json:"devices"`
}

SessionInfo is the response from creating or reconnecting a session.

type Subscription

type Subscription struct {
	// contains filtered or unexported fields
}

Subscription reads events from an SSE stream.

func (*Subscription) Close

func (s *Subscription) Close() error

Close terminates the SSE stream.

func (*Subscription) Next

func (s *Subscription) Next() (Event, error)

Next blocks until the next event is available, the stream closes, or an error occurs. Returns io.EOF when the stream ends.

type WatchValue added in v0.3.1

type WatchValue struct {
	// Frame is the raw frame metadata.
	Frame Frame

	// Value is the decoded PGN struct (e.g. pgn.PositionRapidUpdate).
	// Use a type assertion to access the typed fields.
	Value any
}

WatchValue is a decoded PGN value delivered by Watch.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL