lifxlan: github.com/fishy/lifxlan Index | Examples | Files | Directories

package lifxlan

import "github.com/fishy/lifxlan"

Package lifxlan provides API implemented in Go for LIFX LAN Protocol:

https://lan.developer.lifx.com/v2.0/docs/

This package focuses on the base stuff, device discovery, and capabilities shared by all types of devices. For more concreted capabilities like light control and tile control, please refer to the subpackages.

Currently this package and its subpackages are not complete and implement all possible LIFX LAN Protocols is not the current goal of this package. The design choice for this package is that it exposes as much as possible, so another package can implement missing device APIs by wrapping a device returned by discovery using only exported functions. Please refer to the subpackages for an example of extending device capabilities.

The API is unstable right now, but the maintainer tries very hard not to break them.

This example demonstrates how to do device discovery.

Code:

// Config values that should be initialized with proper args in real code.
var (
    // The target device you want to find.
    target lifxlan.Target
    // The discover timeout.
    timeout time.Duration
)

// It's important to be able to cancel the context.
var ctx context.Context
var cancel context.CancelFunc
if timeout > 0 {
    ctx, cancel = context.WithTimeout(context.Background(), timeout)
} else {
    ctx, cancel = context.WithCancel(context.Background())
}
defer cancel()

deviceChan := make(chan lifxlan.Device)
var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    if err := lifxlan.Discover(ctx, deviceChan, ""); err != nil {
        if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
            log.Fatalf("Discover failed: %v", err)
        }
    }
}()

for device := range deviceChan {
    if !device.Target().Matches(target) {
        continue
    }

    wg.Add(1)
    go func(device lifxlan.Device) {
        defer wg.Done()
        // TODO: handle device

        // If you are satisfied with the device(s) found,
        // you can cancel the context now:
        cancel()
    }(device)
}

wg.Wait()

This example demonstrates how to send a message and wait for the ack.

Please note that this example assumes that no other replies besides ack are expected. If this message will cause a response, you should write your own read loop instead of using WaitForAcks.

Code:

// Should actually be a proper struct according to the Protocol definition.
type payloadType struct{}
// Config values that should be initialized with proper args in real code.
var (
    // Should come with a timeout, or WaitForAcks might wait forever.
    ctx context.Context
    // The discovered device to use.
    device lifxlan.Device
    // The actual message type to be sent.
    message lifxlan.MessageType
    // The actual payload values.
    payload payloadType
)

conn, err := device.Dial()
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

select {
default:
case <-ctx.Done():
    log.Fatal(ctx.Err())
}

seq, err := device.Send(
    ctx,
    conn,
    lifxlan.FlagAckRequired,
    message,
    &payload, // could be nil if this message doesn't need payload.
)
if err != nil {
    log.Fatal(err)
}

if err := lifxlan.WaitForAcks(ctx, conn, device.Source(), seq); err != nil {
    log.Fatal(err)
}

This example demonstrates how to send a message and read the response.

Code:

// Should actually be proper structs according to the Protocol definition.
type (
    payloadType     struct{}
    respPayloadType struct{}
)
// Config values that should be initialized with proper args in real code.
var (
    // Should come with a timeout, or we might wait forever.
    ctx context.Context
    // The discovered device to use.
    device lifxlan.Device
    // The actual message type to be sent.
    message lifxlan.MessageType
    // The actual payload values.
    payload payloadType
    // The response message type.
    respMessage lifxlan.MessageType
)

conn, err := device.Dial()
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

select {
default:
case <-ctx.Done():
    log.Fatal(ctx.Err())
}

seq, err := device.Send(
    ctx,
    conn,
    0,  // flags, not requiring ack because this message will get a response.
    message,
    &payload, // could be nil if this message doesn't need payload.
)
if err != nil {
    log.Fatal(err)
}

for {
    resp, err := lifxlan.ReadNextResponse(ctx, conn)
    if err != nil {
        log.Fatal(err)
    }
    if resp.Sequence != seq || resp.Source != device.Source() {
        continue
    }
    if resp.Message != respMessage {
        continue
    }

    var raw respPayloadType
    r := bytes.NewReader(resp.Payload)
    if err := binary.Read(r, binary.LittleEndian, &raw); err != nil {
        log.Fatal(err)
    }
    // TODO: handle payload value in raw
    return
}

Index

Examples

Package Files

ack.go color.go device.go discover.go doc.go header.go label.go messages.go power.go product_map.go response.go send.go target.go time.go timeout.go version.go

Constants

const (
    KelvinWarm uint16 = 2500
    KelvinCool uint16 = 9000

    KelvinMin uint16 = KelvinWarm
    KelvinMax uint16 = KelvinCool
)

Color value boundaries and constants.

const (
    DefaultBroadcastHost = "255.255.255.255"
    DefaultBroadcastPort = "56700"
)

Default broadcast host and port.

const EmptyHardwareVersion = "(0, 0, 0)"

EmptyHardwareVersion is the constant to be compared against Device.HardwareVersion().String().

const EmptyLabel = ""

EmptyLabel is the constant to be compared against Device.Label().String().

const HeaderLength = 36

HeaderLength is the length of the header

const LabelLength = 32

LabelLength is the length of the raw label used in messages.

const ResponseReadBufferSize = 4096

ResponseReadBufferSize is the recommended buffer size to read UDP responses. It's big enough for all the payloads.

Variables

var ColorBlack = *FromColor(color.Black, 0)

ColorBlack is the black color.

var ProductMap = map[uint64]ParsedHardwareVersion{
    ProductMapKey(1, 1): {
        VendorName:  "LIFX",
        ProductName: "Original 1000",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 3): {
        VendorName:  "LIFX",
        ProductName: "Color 650",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 10): {
        VendorName:  "LIFX",
        ProductName: "White 800 (Low Voltage)",
        Color:       false,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2700,
        MaxKelvin:   6500,
    },
    ProductMapKey(1, 11): {
        VendorName:  "LIFX",
        ProductName: "White 800 (High Voltage)",
        Color:       false,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2700,
        MaxKelvin:   6500,
    },
    ProductMapKey(1, 18): {
        VendorName:  "LIFX",
        ProductName: "White 900 BR30 (Low Voltage)",
        Color:       false,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2700,
        MaxKelvin:   6500,
    },
    ProductMapKey(1, 20): {
        VendorName:  "LIFX",
        ProductName: "Color 1000 BR30",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 22): {
        VendorName:  "LIFX",
        ProductName: "Color 1000",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 27): {
        VendorName:  "LIFX",
        ProductName: "LIFX A19",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 28): {
        VendorName:  "LIFX",
        ProductName: "LIFX BR30",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 29): {
        VendorName:  "LIFX",
        ProductName: "LIFX+ A19",
        Color:       true,
        Infrared:    true,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 30): {
        VendorName:  "LIFX",
        ProductName: "LIFX+ BR30",
        Color:       true,
        Infrared:    true,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 31): {
        VendorName:  "LIFX",
        ProductName: "LIFX Z",
        Color:       true,
        Infrared:    false,
        MultiZone:   true,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 32): {
        VendorName:  "LIFX",
        ProductName: "LIFX Z 2",
        Color:       true,
        Infrared:    false,
        MultiZone:   true,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 36): {
        VendorName:  "LIFX",
        ProductName: "LIFX Downlight",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 37): {
        VendorName:  "LIFX",
        ProductName: "LIFX Downlight",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 38): {
        VendorName:  "LIFX",
        ProductName: "LIFX Beam",
        Color:       true,
        Infrared:    false,
        MultiZone:   true,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 43): {
        VendorName:  "LIFX",
        ProductName: "LIFX A19",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 44): {
        VendorName:  "LIFX",
        ProductName: "LIFX BR30",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 45): {
        VendorName:  "LIFX",
        ProductName: "LIFX+ A19",
        Color:       true,
        Infrared:    true,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 46): {
        VendorName:  "LIFX",
        ProductName: "LIFX+ BR30",
        Color:       true,
        Infrared:    true,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 49): {
        VendorName:  "LIFX",
        ProductName: "LIFX Mini",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 50): {
        VendorName:  "LIFX",
        ProductName: "LIFX Mini Day and Dusk",
        Color:       false,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   1500,
        MaxKelvin:   4000,
    },
    ProductMapKey(1, 51): {
        VendorName:  "LIFX",
        ProductName: "LIFX Mini White",
        Color:       false,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2700,
        MaxKelvin:   2700,
    },
    ProductMapKey(1, 52): {
        VendorName:  "LIFX",
        ProductName: "LIFX GU10",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 55): {
        VendorName:  "LIFX",
        ProductName: "LIFX Tile",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       true,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 59): {
        VendorName:  "LIFX",
        ProductName: "LIFX Mini Color",
        Color:       true,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2500,
        MaxKelvin:   9000,
    },
    ProductMapKey(1, 60): {
        VendorName:  "LIFX",
        ProductName: "LIFX Mini Day and Dusk",
        Color:       false,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   1500,
        MaxKelvin:   4000,
    },
    ProductMapKey(1, 61): {
        VendorName:  "LIFX",
        ProductName: "LIFX Mini White",
        Color:       false,
        Infrared:    false,
        MultiZone:   false,
        Chain:       false,
        MinKelvin:   2700,
        MaxKelvin:   2700,
    },
}

ProductMap is the map of all known hardwares.

If a new product is added and this file is not updated yet, you can add it to the map by yourself, for example:

func init() {
    key := lifxlan.ProductMapKey(newVID, newPID)
    lifxlan.ProductMap[key] = ParsedHardwareVersion{
        // Fill in values
    }
}

The content of this map was fetched from https://github.com/LIFX/products/blob/master/products.json and generated by https://github.com/fishy/lifxlan/tree/master/cmd/gen-product-map

var UDPReadTimeout = time.Millisecond * 100

UDPReadTimeout is the read timeout we use to read all the UDP messages.

In some functions (e.g. Discover), the function will simply use the timeout to check context cancellation and continue reading, instead of return upon timeout.

It's intentionally defined as variable instead of constant, so the user could adjust it if needed.

func CheckTimeoutError Uses

func CheckTimeoutError(err error) bool

CheckTimeoutError returns true if err is caused by timeout in net package.

func Discover Uses

func Discover(
    ctx context.Context,
    devices chan Device,
    broadcastHost string,
) error

Discover discovers lifx products in the lan.

When broadcastHost is empty (""), DefaultBroadcastHost will be used instead. In most cases that should just work. But if your network has special settings, you can override it via the arg.

The function will write discovered devices into devices channel. It's the caller's responsibility to read from channel timely to avoid blocking writing. The function is guaranteed to close the channel upon retuning, so the caller could just range over the channel for reading, e.g.

devices := make(chan Device)
go func() {
  if err := Discover(ctx, devices, ""); err != nil {
    if err != context.DeadlineExceeded {
      // handle error
    }
  }
}()
for device := range devices {
  // Do something with device
}

The function will only return upon error or when ctx is cancelled. It's the caller's responsibility to make sure that the context is cancelled (e.g. Use context.WithTimeout).

func GenerateMessage Uses

func GenerateMessage(
    tagged TaggedHeader,
    source uint32,
    target Target,
    flags AckResFlag,
    sequence uint8,
    message MessageType,
    payload []byte,
) ([]byte, error)

GenerateMessage generates the message to send.

func GetReadDeadline Uses

func GetReadDeadline() time.Time

GetReadDeadline returns a value can be used in net.Conn.SetReadDeadline from UDPReadTimeout value.

func ProductMapKey Uses

func ProductMapKey(vendor, product uint32) uint64

ProductMapKey generates key for ProductMap based on vendor and product ids.

func RandomSource Uses

func RandomSource() uint32

RandomSource generates a random number to be used as source. It's guaranteed to be non-zero.

func WaitForAcks Uses

func WaitForAcks(
    ctx context.Context,
    conn net.Conn,
    source uint32,
    sequences ...uint8,
) error

WaitForAcks helps device API implementations to wait for acks.

It blocks until acks for all sequences are received, in which case it returns nil error. It also returns when the context is cancelled.

This function drops all received messages that is not an ack, or ack messages that the sequence and source don't match. Therefore, there shouldn't be more than one WaitForAcks functions running for the same connection at the same time, and this function should only be used when no other responses are expected.

If this function returns an error, the error would be of type *WaitForAcksError.

type AckResFlag Uses

type AckResFlag uint8

AckResFlag is the 8-bit header that could include:

- ack_required: if set all sent messages will expect an ack response.

- res_required: if set all sent messages will expect a response.

const (
    FlagResRequired AckResFlag = 1 << iota
    FlagAckRequired
)

AckResFlag values.

type Color Uses

type Color struct {
    Hue        uint16
    Saturation uint16
    Brightness uint16
    Kelvin     uint16
}

Color is the HSBK color type used in lifx lan API.

https://lan.developer.lifx.com/v2.0/docs/light-messages#section-hsbk

func FromColor Uses

func FromColor(c color.Color, kelvin uint16) *Color

FromColor converts a standard library color into HSBK color.

Alpha channel will be ignored and kelvin value will be added.

func (*Color) Sanitize Uses

func (c *Color) Sanitize()

Sanitize tries to sanitize the color values to keep them within appropriate boundaries, based on default boundaries.

type Device Uses

type Device interface {
    // Target returns the target of this device, usually it's the MAC address.
    Target() Target

    // Dial tries to establish a connection to this device.
    Dial() (net.Conn, error)

    // Source returns a consistent random source to be used with API calls.
    // It's guaranteed to be non-zero.
    Source() uint32

    // NextSequence returns the next sequence value to be used with API calls.
    NextSequence() uint8

    // Send generates and sends a message to the device.
    //
    // conn must be pre-dialed or this function will fail.
    //
    // It calls the device's Target(), Source(), and NextSequence() functions to
    // fill the appropriate headers.
    //
    // The sequence used in this message will be returned.
    Send(ctx context.Context, conn net.Conn, flags AckResFlag, message MessageType, payload interface{}) (seq uint8, err error)

    // SanitizeColor tries to sanitize (keep values inside appropriate boundaries)
    // color based on the device's hardware version, if available.
    //
    // If the device's hardware version was never fetched and cached,
    // it uses default boundaries (see doc for Color.Sanitize).
    SanitizeColor(color Color) Color

    // GetPower returns the current power level of the device.
    //
    // If conn is nil,
    // a new connection will be made and guaranteed to be closed before returning.
    // You should pre-dial and pass in the conn if you plan to call APIs on this
    // device repeatedly.
    GetPower(ctx context.Context, conn net.Conn) (Power, error)
    // SetPower sets the power level of the device.
    // (Turn it on or off.)
    //
    // If conn is nil,
    // a new connection will be made and guaranteed to be closed before returning.
    // You should pre-dial and pass in the conn if you plan to call APIs on this
    // device repeatedly.
    //
    // If ack is false,
    // this function returns nil error after the API is sent successfully.
    // If ack is true,
    // this function will only return nil error after it received ack from the
    // device.
    SetPower(ctx context.Context, conn net.Conn, power Power, ack bool) error

    // The label of the device.
    Label() *Label
    GetLabel(ctx context.Context, conn net.Conn) error

    // The hardware version info of the device.
    HardwareVersion() *HardwareVersion
    GetHardwareVersion(ctx context.Context, conn net.Conn) error
}

Device defines the common interface between lifxlan devices.

For the Foo() and GetFoo() function pairs (e.g. Label() and GetLabel()), the Foo() one will return an pointer to the cached property, guaranteed to be non-nil but could be the zero value, while the GetFoo() one will use an API call to update the cached property.

There will also be an EmptyFoo string constant defined, so that you can compare against Device.Foo().String() to determine if a GetFoo() call is needed. Here is an example code snippet to get a device's label:

func GetLabel(ctx context.Context, d lifxlanDevice) (string, error) {
    if d.Label().String() != lifxlan.EmptyLabel {
        return d.Label().String(), nil
    }
    if err := d.GetLabel(ctx, nil); err = nil {
        return "", nil
    }
    return d.Label().String(), nil
}

If you are extending a device code and you got the property as part of another API's return payload, you can also use the Foo() function to update the cached value. Here is an example code snippet to update a device's cached label:

func UpdateLabel(d lifxlanDevice, newLabel *lifxlan.RawLabel) {
    *d.Label() = *newLabel
}

The conn arg in GetFoo() functions can be nil. In such cases, a new connection will be made and guaranteed to be closed before returning. You should pre-dial and pass in the conn if you plan to call APIs on this device repeatedly.

In case of network error (e.g. response packet loss), the GetFoo() functions might block until the context is cancelled, as a result, it's a good idea to set a timeout to the context.

func NewDevice Uses

func NewDevice(addr string, service ServiceType, target Target) Device

NewDevice creates a new Device.

addr must be in "host:port" format and service must be a known service type, otherwise the later Dial funcion will fail.

type HardwareVersion Uses

type HardwareVersion struct {
    VendorID        uint32
    ProductID       uint32
    HardwareVersion uint32
}

HardwareVersion defines raw version info in message payloads according to:

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-stateversion-33

func (HardwareVersion) Parse Uses

func (raw HardwareVersion) Parse() *ParsedHardwareVersion

Parse parses the raw hardware version info by looking up ProductMap.

If this hardware version info is not in ProductMap, nil will be returned.

func (HardwareVersion) ProductMapKey Uses

func (raw HardwareVersion) ProductMapKey() uint64

ProductMapKey generates key for ProductMap.

func (HardwareVersion) String Uses

func (raw HardwareVersion) String() string

type Label Uses

type Label [LabelLength]byte

Label defines raw label in message payloads according to:

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-labels

func (Label) Get Uses

func (l Label) Get() interface{}

Get implements flag.Getter interface.

func (*Label) Set Uses

func (l *Label) Set(label string) error

Set encodes label into Label.

Long labels will be truncated. This function always return nil error.

It also implements flag.Value interface.

func (Label) String Uses

func (l Label) String() string

type MessageType Uses

type MessageType uint16

MessageType is the 16-bit header indicates the type of the message.

const (
    Acknowledgement MessageType = 45
    GetService      MessageType = 2
    StateService    MessageType = 3
    GetPower        MessageType = 20
    StatePower      MessageType = 22
    SetPower        MessageType = 21
    GetLabel        MessageType = 23
    StateLabel      MessageType = 25
    GetVersion      MessageType = 32
    StateVersion    MessageType = 33
)

MessageType values.

type ParsedHardwareVersion Uses

type ParsedHardwareVersion struct {
    VendorName  string
    ProductName string

    // Features
    Color     bool
    Infrared  bool
    MultiZone bool
    Chain     bool
    // Both values are inclusive.
    MinKelvin uint16
    MaxKelvin uint16

    // Embedded raw info.
    Raw HardwareVersion
}

ParsedHardwareVersion is the parsed hardware version info.

type Power Uses

type Power uint16

Power is the raw power level value in messages.

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-power-level

const (
    PowerOn  Power = 65535
    PowerOff Power = 0
)

Power values.

func (Power) On Uses

func (p Power) On() bool

On returns whether this power level value represents on state.

func (Power) String Uses

func (p Power) String() string

type RawHeader Uses

type RawHeader struct {
    Size   uint16
    Tagged TaggedHeader
    Source uint32
    Target Target

    Flags    AckResFlag
    Sequence uint8

    Type MessageType
    // contains filtered or unexported fields
}

RawHeader defines the struct to be used for encoding and decoding.

https://lan.developer.lifx.com/v2.0/docs/header-description

type RawSetPowerPayload Uses

type RawSetPowerPayload struct {
    Level Power
}

RawSetPowerPayload defines the struct to be used for encoding and decoding.

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-setpower-21

type RawStateLabelPayload Uses

type RawStateLabelPayload struct {
    Label Label
}

RawStateLabelPayload defines the struct to be used for encoding and decoding.

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-statelabel-25

type RawStatePowerPayload Uses

type RawStatePowerPayload struct {
    Level Power
}

RawStatePowerPayload defines the struct to be used for encoding and decoding.

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-statepower-22

type RawStateServicePayload Uses

type RawStateServicePayload struct {
    Service ServiceType
    Port    uint32
}

RawStateServicePayload defines the struct to be used for encoding and decoding.

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-stateservice-3

type RawStateVersionPayload Uses

type RawStateVersionPayload struct {
    Version HardwareVersion
}

RawStateVersionPayload defines the struct to be used for encoding and decoding.

https://lan.developer.lifx.com/v2.0/docs/device-messages#section-stateversion-33

type Response Uses

type Response struct {
    Message  MessageType
    Flags    AckResFlag
    Source   uint32
    Target   Target
    Sequence uint8
    Payload  []byte
}

Response is the parsed response from a lifxlan device.

func ParseResponse Uses

func ParseResponse(msg []byte) (*Response, error)

ParseResponse parses the response received from a lifxlan device.

func ReadNextResponse Uses

func ReadNextResponse(ctx context.Context, conn net.Conn) (*Response, error)

ReadNextResponse returns the next received response.

It handles read buffer, deadline, context cancellation check, and response parsing.

type ServiceType Uses

type ServiceType uint8

ServiceType define the type of the service this device provides.

const (
    ServiceUDP ServiceType = 1
)

Documented values for ServiceType.

func (ServiceType) String Uses

func (s ServiceType) String() string

type TaggedHeader Uses

type TaggedHeader uint16

TaggedHeader is the 16-bit header including:

- origin: 2 bits, must be 0

- tagged: 1 bit

- addressable: 1 bit, must be 1

- protocol: 12 bits, must be 1024

const (
    NotTagged TaggedHeader = 1<<12 + 1024
    Tagged    TaggedHeader = 1<<13 + NotTagged
)

Tagged and non-tagged versions of TaggedHeader.

type Target Uses

type Target uint64

Target defines a target by its MAC address.

const AllDevices Target = 0

AllDevices is the special Target value means all devices.

func ParseTarget Uses

func ParseTarget(s string) (t Target, err error)

ParseTarget parses s into a Target.

s should be in the format of a MAC address, e.g. "01:23:45:67:89:ab", or the special values for AllDevices: "00:00:00:00:00:00" and "".

func (Target) Get Uses

func (t Target) Get() interface{}

Get implements flag.Getter interface.

func (Target) Matches Uses

func (t Target) Matches(other Target) bool

Matches returns true if either target is AllDevices, or both targets have the same value.

func (*Target) Set Uses

func (t *Target) Set(s string) (err error)

Set implements flag.Value interface.

It calls ParseTarget to parse the string. Refer to the doc of ParseTarget for more details.

Code:

var target lifxlan.Target
flag.Var(
    &target,
    "target",
    "The MAC address of the target device. Empty value means any device.",
)
flag.Parse()

func (Target) String Uses

func (t Target) String() string

type Timestamp Uses

type Timestamp uint64

Timestamp is the type used in messages to represent a timestamp.

It's defined as nanoseconds since UNIX EPOCH.

func ConvertTime Uses

func ConvertTime(t time.Time) Timestamp

ConvertTime converts a time.Time into Timestamp.

func (Timestamp) String Uses

func (ts Timestamp) String() string

func (Timestamp) Time Uses

func (ts Timestamp) Time() time.Time

Time converts a Timestamp into time.Time.

type TransitionTime Uses

type TransitionTime uint32

TransitionTime is the type used in messages to represent transition time.

Its unit is milliseconds.

func ConvertDuration Uses

func ConvertDuration(d time.Duration) TransitionTime

ConvertDuration converts a time.Duration into TransitionTime.

The max uint32 value can represent a transition time of more than 1,193 hours[1] (or, in other words, more than a month). So although an overflow is technically possible, we don't really do any special handlings here (it's not a security risk and won't crash anything[2]). If you feed in a duration that overflows TransitionTime, you should feel bad (or great, it's totally up to you) about it. Do you really want your light(s) to take more than a month to turn on/off?

[1] https://play.golang.com/p/LqfMpvhIctx

[2] https://play.golang.com/p/edwqG4nNqkt

func (TransitionTime) Duration Uses

func (tt TransitionTime) Duration() time.Duration

Duration converts a TransitionTime into time.Duration.

func (TransitionTime) String Uses

func (tt TransitionTime) String() string

type WaitForAcksError Uses

type WaitForAcksError struct {
    Received []uint8
    Total    []uint8
    Cause    error
}

WaitForAcksError defines the error returned by WaitForAcks.

func (*WaitForAcksError) Error Uses

func (e *WaitForAcksError) Error() string

Directories

PathSynopsis
cmd/gen-product-mapCommand gen-product-map is the helper tool to generate lifxlan ProductMap.
lightPackage light implements LIFX LAN Protocol for LIFX light devices:
mockPackage mock implements a mocked lifxlan device listening on localhost, which can be used in test code to test API calls.
tilePackage tile implements LIFX LAN Protocol for LIFX Tile devices:

Package lifxlan imports 13 packages (graph) and is imported by 3 packages. Updated 2019-02-25. Refresh now. Tools for package owners.