ota

package
v0.4.3 Latest Latest
Warning

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

Go to latest
Published: Feb 6, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package ota implements Over-The-Air (OTA) firmware update functionality for Zigbee devices using the Zigbee OTA Upgrade Cluster (0x0019).

Overview

OTA upgrades allow Zigbee devices to receive firmware updates over the Zigbee network without requiring physical access or a USB connection. This package provides both OTA image parsing and an OTA server for serving firmware to devices.

OTA File Format

Zigbee OTA upgrade files follow the Zigbee specification (07-5123-06). The file contains:

[Upgrade File ID] [Header] [Sub-elements] [Image Data]

The Upgrade File ID is a magic number (0x0BEEF11E) that identifies valid OTA files. The header contains metadata about the firmware including:

  • Manufacturer code and image type
  • Firmware version
  • Zigbee stack version compatibility
  • Hardware version ranges

Sub-elements contain optional information like:

  • Security credentials (ECDH, ECDSA signatures)
  • Image signing certificates
  • Manufacturer-specific data

Basic Usage - Loading OTA Images

// Load an OTA file
img, err := ota.ParseFile("/path/to/firmware.ota")
if err != nil {
    log.Fatal(err)
}

// Check image metadata
fmt.Printf("Version: %s\n", img.GetVersionString())
fmt.Printf("Manufacturer: 0x%04X\n", img.ManufacturerCode)
fmt.Printf("Image Type: 0x%04X\n", img.ImageType)
fmt.Printf("Size: %d bytes\n", img.ImageSize)

// Validate compatibility with a device
err = img.Validate(deviceManufacturer, deviceImageType, deviceVersion)

Basic Usage - OTA Server

// Create an OTA server with images in a directory
server, err := ota.NewServer(ota.ServerConfig{
    ImagesDir: "/path/to/ota/files",
    MaxBlockSize: 64,
})
if err != nil {
    log.Fatal(err)
}

// Set the server address to coordinator's IEEE address
server.SetServerAddr(coordinatorIEEEAddr)

// Handle Query Image command from device
resp, err := server.QueryImage(ctx, ota.QueryImageCommand{
    ManufacturerCode: 0x115F, // Tuya
    ImageType:        0x2200,
    FileVersion:      0x1234,
}, "00:11:22:33:44:55:66:77")

// Handling OTA Requests from Devices

When a device is performing an OTA update, it will send these commands:

1. Query Image - Device asks if an update is available
2. Image Block - Device requests chunks of firmware data
3. Upgrade End - Device signals completion (success/failure)

These are typically handled by the adapter layer which calls into
the OTA server. See the goznp adapter package for integration.

Progress Monitoring

// Set up progress callback
server.OnProgress = func(update ota.ProgressUpdate) {
    fmt.Printf("[%s] %.1f%% complete - %d/%d bytes\n",
        update.Device, update.Percentage,
        update.Offset, update.TotalSize)
}

// Or monitor via channel
updates, err := server.MonitorProgress(ctx, deviceIEEEAddr)
if err != nil {
    log.Fatal(err)
}
for update := range updates {
    fmt.Printf("Progress: %.1f%%\n", update.Percentage)
}

Image Management

// List all available images
images := server.ListImages()
for _, img := range images {
    fmt.Printf("%s - %s (%d bytes)\n",
        img.GetVersionString(), img.HeaderString, img.ImageSize)
}

// Add a custom image
img, _ := ota.ParseBytes(otaData)
server.AddImage(img)

// Remove an image
server.RemoveImage(manufacturer, imageType, fileVersion)

Sub-elements

Sub-elements contain optional metadata about the image:

// Get ECDSA signature
signature := img.GetECDSASignature()

// Get signing certificate
cert := img.GetSigningCertificate()

// Get any sub-element by tag
se := img.GetSubElement(ota.TagSigningCertificate)

Thread Safety

The OTA Server is safe for concurrent use from multiple goroutines. All methods use internal mutex protection.

Security Considerations

OTA images should be verified for authenticity:

  • Check the upgrade file ID (0x0BEEF11E)
  • Validate ECDSA signatures if present
  • Ensure images come from trusted sources
  • Use install codes for secure device joining
  • Verify manufacturer and image type before serving

Package ota implements OTA (Over-The-Air) firmware update functionality for Zigbee devices using the Zigbee OTA Upgrade cluster (0x0019).

This package provides:

  • OTA image file parsing (Zigbee OTA Upgrade file format).
  • OTA server implementation for serving firmware to devices.
  • Progress tracking for ongoing updates.

Index

Constants

View Source
const (
	// UpgradeFileID marks a valid OTA upgrade file.
	UpgradeFileID = 0x0BEEF11E

	// HeaderVersion supported by this implementation.
	HeaderVersion = 0x0100

	// Field control bit positions.
	FCSecurityCredentialVers uint16 = 0x0001
	FCDeviceSpecificFile     uint16 = 0x0002
	FCHardwareVersions       uint16 = 0x0004
	FCMinApplicable          uint16 = 0x0040
	FCMinAppHardwareVers     uint16 = 0x0080
)

Variables

This section is empty.

Functions

This section is empty.

Types

type FileHeader

type FileHeader struct {
	// OTA header fields.
	UpgradeFileID      uint32 // Must be 0x0BEEF11E for upgrade files.
	HeaderVersion      uint16 // Must be 0x0100 for version 1.0.
	HeaderLength       uint16 // Length of this header in bytes.
	HeaderFieldControl uint16 // Bitmask indicating which fields are present.
	ManufacturerCode   uint16 // Manufacturer-specific code.
	ImageType          uint16 // Manufacturer-defined image type identifier.
	FileVersion        uint32 // Version of the firmware image.
	StackVersion       uint16 // Version of the Zigbee stack.
	HeaderString       string // "Image header v" followed by version.
	ImageSize          uint32 // Size of the complete image in bytes.

	// Optional fields (based on HeaderFieldControl).
	SecurityCredentialVers uint8  // Version of security credentials (if BC-01).
	DeviceSpecificFile     bool   // True if this file is device-specific.
	MinHardwareVersion     uint16 // Minimum supported hardware version.
	MaxHardwareVersion     uint16 // Maximum supported hardware version.
	HeaderBitmap           uint32 // Bitmap indicating other optional header fields.

}

FileHeader represents the header of an OTA upgrade file. Based on Zigbee specification 07-5123-06 (Zigbee Over-The-Air Upgrade).

type FirmwareMatch

type FirmwareMatch struct {
	Image        *Image // Parsed OTA image.
	Manufacturer uint16 // Manufacturer code.
	ImageType    uint16 // Image type identifier.
	FileVersion  uint32 // Firmware version.
	Compatible   bool   // Whether this firmware is compatible.
}

FirmwareMatch represents matching firmware for a device.

type Image

type Image struct {
	FileHeader
	SubElements []SubElement
	ImageData   []byte // Raw firmware data.
	RawBytes    []byte // Complete file contents.
	Path        string // File path if loaded from disk.
}

Image represents a parsed OTA upgrade file.

func ParseBytes

func ParseBytes(data []byte) (*Image, error)

ParseBytes parses an OTA upgrade file from byte data.

func ParseFile

func ParseFile(path string) (*Image, error)

ParseFile reads and parses an OTA upgrade file from disk.

func (*Image) BlockSize

func (img *Image) BlockSize() uint8

BlockSize returns the recommended block size for this image. Most devices support block sizes between 16 and 64 bytes.

func (*Image) GetECDSASignature

func (img *Image) GetECDSASignature() []byte

GetECDSASignature returns the ECDSA signature sub-element if present.

func (*Image) GetSigningCertificate

func (img *Image) GetSigningCertificate() []byte

GetSigningCertificate returns the signing certificate sub-element if present.

func (*Image) GetSubElement

func (img *Image) GetSubElement(tagID ImageHeaderTag) *SubElement

GetSubElement returns a sub-element by its tag ID, or nil if not found.

func (*Image) GetVersionString

func (img *Image) GetVersionString() string

GetVersionString returns a human-readable version string. Zigbee OTA version format: major (byte 3), minor (byte 2), patch (byte 1), build (byte 0).

func (*Image) ImageFile

func (i *Image) ImageFile() uint16

ImageFile returns the image type for lookup purposes.

func (*Image) IsCompatible

func (img *Image) IsCompatible(deviceManufacturer uint16, deviceImageType uint16, deviceVersion uint32) bool

IsCompatible checks if this image is compatible with the given device. Unlike Validate, this returns a boolean and doesn't require version to be higher.

func (*Image) NextBlockOffset

func (img *Image) NextBlockOffset(offset uint32, maxSize uint8) (nextOffset uint32, dataSize uint8, finished bool)

NextBlockOffset calculates the next block offset and size for a given offset.

func (*Image) Validate

func (img *Image) Validate(deviceManufacturer uint16, deviceImageType uint16, deviceVersion uint32) error

Validate checks if the OTA image is valid for the given device.

type ImageBlockRequest

type ImageBlockRequest struct {
	FieldControl     uint8  // Bitmask for optional fields.
	ManufacturerCode uint16 // Manufacturer code.
	ImageType        uint16 // Image type identifier.
	FileVersion      uint32 // Firmware version being requested.
	FileOffset       uint32 // Byte offset of requested block.
	MaximumDataSize  uint8  // Maximum data size for this block.
}

ImageBlockRequest represents the OTA cluster Image Block request. Sent by the client to request a block of firmware data.

type ImageBlockResponse

type ImageBlockResponse struct {
	Status           uint8  // 0x00=Success.
	ManufacturerCode uint16 // Manufacturer code.
	ImageType        uint16 // Image type identifier.
	FileVersion      uint32 // Firmware version.
	FileOffset       uint32 // Byte offset of this block.
	DataSize         uint8  // Length of the following data.
	Data             []byte // Firmware data block.
}

ImageBlockResponse represents the OTA cluster Image Block response. Sent by the server containing firmware data.

type ImageHeaderTag

type ImageHeaderTag uint16

ImageHeaderTag identifies optional sub-element types.

const (
	TagECDHInfo            ImageHeaderTag = 0x0001 // Elliptic Curve Diffie-Hellman info.
	TagECDSASignature      ImageHeaderTag = 0x0002 // Elliptic Curve Digital Signature Algorithm.
	TagImageLayout         ImageHeaderTag = 0x0003 // Manufacturer-defined layout.
	TagSigningCertificate  ImageHeaderTag = 0x0004 // Certificate for image signing.
	TagWholeImageSignature ImageHeaderTag = 0x0005 // Signature for the entire image.
	TagZigbeePlatformInfo  ImageHeaderTag = 0x0006 // Zigbee platform-specific info.
)

func (ImageHeaderTag) String added in v0.2.1

func (t ImageHeaderTag) String() string

type OTAStatus

type OTAStatus uint8

OTAStatus represents OTA operation status codes.

const (
	StatusSuccess           OTAStatus = 0x00 // Operation successful.
	StatusInvalidImage      OTAStatus = 0x81 // Invalid image.
	StatusRequiresMoreImage OTAStatus = 0x82 // Requires more images.
	StatusNotAuthorized     OTAStatus = 0x83 // Not authorized.
	StatusAbort             OTAStatus = 0x95 // Abort operation.
	StatusAbortWaitForData  OTAStatus = 0x96 // Abort, wait for data.
	StatusWaitForData       OTAStatus = 0x97 // Wait for more data.
	StatusNoImageAvailable  OTAStatus = 0x98 // No image available.
)

func (OTAStatus) String

func (s OTAStatus) String() string

type ProgressUpdate

type ProgressUpdate struct {
	Device      string  // IEEE address.
	FileVersion uint32  // File version.
	Offset      uint32  // Current offset.
	TotalSize   uint32  // Total file size.
	Percentage  float64 // Completion percentage.
	Status      string  // Status message.
	Error       error   // Error if any.
}

ProgressUpdate represents a single progress update.

type QueryImageCommand

type QueryImageCommand struct {
	FieldControl     uint8  // Bitmask for optional fields.
	ManufacturerCode uint16 // Manufacturer code.
	ImageType        uint16 // Image type identifier.
	FileVersion      uint32 // Current firmware version.
	HardwareVersion  uint16 // Current hardware version.
}

QueryImageCommand represents the OTA cluster Query Image command. Sent by the client to request firmware update information.

type QueryImageResponse

type QueryImageResponse struct {
	Status            uint8   // 0x00=Success, 0x80=Abort, 0x81=Not authorized, etc.
	ManufacturerCode  uint16  // Manufacturer code.
	ImageType         uint16  // Image type identifier.
	FileVersion       uint32  // New firmware file version.
	ImageSize         uint32  // Size of the firmware image in bytes.
	ServerAddress     [8]byte // IEEE address of the OTA server.
	MinimumBlockDelay uint16  // Minimum delay between block requests (ms).
	MaximumBlockDelay uint16  // Maximum delay between block requests (ms).
}

QueryImageResponse represents the OTA cluster Query Image response. Sent by the server to update availability and file information.

type Server

type Server struct {

	// Callbacks for progress updates.
	OnProgress func(ProgressUpdate)
	OnComplete func(device string, fileVersion uint32)
	OnError    func(device string, err error)
	// contains filtered or unexported fields
}

Server handles OTA upgrade requests from Zigbee devices. It serves firmware images and tracks upgrade progress.

func NewServer

func NewServer(config ServerConfig) (*Server, error)

NewServer creates a new OTA server with the given configuration.

func (*Server) AddImage

func (s *Server) AddImage(img *Image)

AddImage adds an OTA image to the server's image database.

func (*Server) GetImage

func (s *Server) GetImage(manufacturer uint16, imageType uint16, fileVersion uint32) (*Image, error)

GetImage retrieves an OTA image by manufacturer and image type. Returns the latest version if fileVersion is 0, or specific version otherwise.

func (*Server) GetProgress

func (s *Server) GetProgress(deviceAddr string) (*UpgradeProgress, error)

GetProgress returns the current progress for a device.

func (*Server) GetServerAddr

func (s *Server) GetServerAddr() [8]byte

GetServerAddr returns the IEEE address of the OTA server.

func (*Server) ImageBlock

func (s *Server) ImageBlock(_ context.Context, req ImageBlockRequest, deviceAddr string) (*ImageBlockResponse, error)

ImageBlock handles an Image Block request from a device. Returns the appropriate Image Block Response.

func (*Server) IsActiveCheck

func (s *Server) IsActiveCheck(deviceAddr string) bool

IsActiveCheck checks if a device has an active OTA upgrade in progress.

func (*Server) ListImages

func (s *Server) ListImages() []*Image

ListImages returns all images available in the server.

func (*Server) MonitorProgress

func (s *Server) MonitorProgress(ctx context.Context, deviceAddr string) (<-chan ProgressUpdate, error)

MonitorProgress starts monitoring progress for a device via a channel.

func (*Server) QueryImage

func (s *Server) QueryImage(_ context.Context, req QueryImageCommand, _ string) (*QueryImageResponse, error)

QueryImage handles a Query Image command from a device. Returns the appropriate Query Image Response.

func (*Server) RemoveImage

func (s *Server) RemoveImage(manufacturer uint16, imageType uint16, fileVersion uint32)

RemoveImage removes an OTA image from the server's database.

func (*Server) SetServerAddr

func (s *Server) SetServerAddr(addr [8]byte)

SetServerAddr sets the IEEE address of the OTA server. This is typically the coordinator's IEEE address.

func (*Server) UpgradeEnd

func (s *Server) UpgradeEnd(_ context.Context, req UpgradeEndRequest, deviceAddr string) (*UpgradeEndResponse, error)

UpgradeEnd handles an Upgrade End request from a device. Returns the appropriate Upgrade End Response.

type ServerConfig

type ServerConfig struct {
	// ImagesDir is the directory containing OTA firmware files.
	ImagesDir string

	// MaxBlockSize is the maximum block size to serve (default: 64).
	MaxBlockSize uint8

	// MinBlockDelay is the minimum delay between block requests (default: 50ms).
	MinBlockDelay uint16

	// MaxBlockDelay is the maximum delay between block requests (default: 500ms).
	MaxBlockDelay uint16

	// ServerAddr is the IEEE address of the OTA server (defaults to coordinator address).
	ServerAddr [8]byte

	// Progress callbacks.
	OnProgress func(ProgressUpdate)
	OnComplete func(device string, fileVersion uint32)
	OnError    func(device string, err error)
}

ServerConfig holds configuration for the OTA server.

type SubElement

type SubElement struct {
	TagID  uint16 // Identifies the type of sub-element.
	Length uint32 // Length of the data in bytes.
	Data   []byte // Sub-element data.
}

SubElement represents an optional sub-element in the OTA file.

type UpgradeEndRequest

type UpgradeEndRequest struct {
	Status           uint8  // 0x00=Success, 0x81=Invalid image, etc.
	ManufacturerCode uint16 // Manufacturer code.
	ImageType        uint16 // Image type identifier.
	FileVersion      uint32 // Firmware version applied.
}

UpgradeEndRequest represents the OTA cluster Upgrade End request. Sent by the client when the upgrade is complete.

type UpgradeEndResponse

type UpgradeEndResponse struct {
	ManufacturerCode uint16 // Echoed from request.
	ImageType        uint16 // Echoed from request.
	FileVersion      uint32 // Echoed from request.
	Applicability    uint8  // 0x01=Downgraded, 0x02=Same version, 0x03=Upgraded.
}

UpgradeEndResponse represents the OTA cluster Upgrade End response. Sent by the server to acknowledge the upgrade completion.

type UpgradeProgress

type UpgradeProgress struct {
	IEEEAddress    string              // IEEE address of the device.
	FileVersion    uint32              // File version being downloaded.
	TotalSize      uint32              // Total size of the firmware.
	DownloadedSize uint32              // Bytes downloaded so far.
	Percentage     float64             // Completion percentage (0-100).
	ProgressChan   chan ProgressUpdate // Channel for progress updates.
}

UpgradeProgress tracks the progress of an OTA update.

Jump to

Keyboard shortcuts

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