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
- type FileHeader
- type FirmwareMatch
- type Image
- func (img *Image) BlockSize() uint8
- func (img *Image) GetECDSASignature() []byte
- func (img *Image) GetSigningCertificate() []byte
- func (img *Image) GetSubElement(tagID ImageHeaderTag) *SubElement
- func (img *Image) GetVersionString() string
- func (i *Image) ImageFile() uint16
- func (img *Image) IsCompatible(deviceManufacturer uint16, deviceImageType uint16, deviceVersion uint32) bool
- func (img *Image) NextBlockOffset(offset uint32, maxSize uint8) (nextOffset uint32, dataSize uint8, finished bool)
- func (img *Image) Validate(deviceManufacturer uint16, deviceImageType uint16, deviceVersion uint32) error
- type ImageBlockRequest
- type ImageBlockResponse
- type ImageHeaderTag
- type OTAStatus
- type ProgressUpdate
- type QueryImageCommand
- type QueryImageResponse
- type Server
- func (s *Server) AddImage(img *Image)
- func (s *Server) GetImage(manufacturer uint16, imageType uint16, fileVersion uint32) (*Image, error)
- func (s *Server) GetProgress(deviceAddr string) (*UpgradeProgress, error)
- func (s *Server) GetServerAddr() [8]byte
- func (s *Server) ImageBlock(_ context.Context, req ImageBlockRequest, deviceAddr string) (*ImageBlockResponse, error)
- func (s *Server) IsActiveCheck(deviceAddr string) bool
- func (s *Server) ListImages() []*Image
- func (s *Server) MonitorProgress(ctx context.Context, deviceAddr string) (<-chan ProgressUpdate, error)
- func (s *Server) QueryImage(_ context.Context, req QueryImageCommand, _ string) (*QueryImageResponse, error)
- func (s *Server) RemoveImage(manufacturer uint16, imageType uint16, fileVersion uint32)
- func (s *Server) SetServerAddr(addr [8]byte)
- func (s *Server) UpgradeEnd(_ context.Context, req UpgradeEndRequest, deviceAddr string) (*UpgradeEndResponse, error)
- type ServerConfig
- type SubElement
- type UpgradeEndRequest
- type UpgradeEndResponse
- type UpgradeProgress
Constants ¶
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 ¶
ParseBytes parses an OTA upgrade file from byte data.
func (*Image) BlockSize ¶
BlockSize returns the recommended block size for this image. Most devices support block sizes between 16 and 64 bytes.
func (*Image) GetECDSASignature ¶
GetECDSASignature returns the ECDSA signature sub-element if present.
func (*Image) GetSigningCertificate ¶
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 ¶
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) 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.
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. )
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) 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 ¶
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 ¶
IsActiveCheck checks if a device has an active OTA upgrade in progress.
func (*Server) ListImages ¶
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 ¶
RemoveImage removes an OTA image from the server's database.
func (*Server) SetServerAddr ¶
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.