|
|
package nanoleaf
import ( "encoding/binary" "git.aiterp.net/lucifer3/server/device" "git.aiterp.net/lucifer3/server/internal/color" "time" )
type EffectInfo struct { EffectsList []string `json:"effectsList"` Select string `json:"select"` }
type PanelLayout struct { GlobalOrientation GlobalOrientation `json:"globalOrientation"` Data PanelLayoutData `json:"layout"` }
type GlobalOrientation struct { Value int `json:"value"` Max int `json:"max"` Min int `json:"min"` }
type PanelLayoutData struct { NumPanels int `json:"numPanels"` SideLength int `json:"sideLength"` PositionData []PositionData `json:"positionData"` }
type PositionData struct { PanelID uint16 `json:"panelId"` X int `json:"x"` Y int `json:"y"` O int `json:"o"` ShapeType int `json:"shapeType"` }
type StateBool struct { Value bool `json:"value"` }
type StateInt struct { Value int `json:"value"` Max int `json:"max"` Min int `json:"min"` }
type State struct { Brightness StateInt `json:"brightness"` ColorMode string `json:"colorMode"` Ct StateInt `json:"ct"` Hue StateInt `json:"hue"` On StateBool `json:"on"` Sat StateInt `json:"sat"` }
type Overview struct { Name string `json:"name"` SerialNumber string `json:"serialNo"` Manufacturer string `json:"manufacturer"` FirmwareVersion string `json:"firmwareVersion"` HardwareVersion string `json:"hardwareVersion"` Model string `json:"model"` Effects EffectInfo `json:"effects"` PanelLayout PanelLayout `json:"panelLayout"` State State `json:"state"` }
type DeviceInfo struct { SerialNumber string `json:"serialNumber"` HardwareVersion string `json:"hardwareVersion"` FirmwareVersion string `json:"firmwareVersion"` BootloaderVersion string `json:"bootloaderVersion"` ModelNumber string `json:"modelNumber"` }
type TokenResponse struct { Token string `json:"auth_token"` }
type PanelUpdate []byte
func (u *PanelUpdate) Add(message [8]byte) { if len(*u) < 2 { *u = make([]byte, 2, 10) }
binary.BigEndian.PutUint16(*u, binary.BigEndian.Uint16(*u)+1)
*u = append(*u, message[:]...) }
func (u *PanelUpdate) Len() int { if len(*u) < 2 { return 0 }
return int(binary.BigEndian.Uint16(*u)) }
type PanelEventMessage []byte
func (remote PanelEventMessage) Count() int { return int(binary.BigEndian.Uint16(remote[0:])) }
func (remote PanelEventMessage) ValidateLength() bool { return len(remote) >= (2 + remote.Count()*5) }
func (remote PanelEventMessage) PanelID(idx int) uint16 { return binary.BigEndian.Uint16(remote[2+(idx*5):]) }
func (remote PanelEventMessage) TouchType(idx int) int { value := int(remote[2+(idx*5)]) return (value & 0b11100000) >> 5 }
func (remote PanelEventMessage) TouchStrength(idx int) int { value := int(remote[2+(idx*5)]) return (value & 0b00011110) >> 1 }
func (remote PanelEventMessage) SwipedFromPanelID(idx int) uint16 { return binary.BigEndian.Uint16(remote[2+(idx*5)+3:]) }
var shapeTypeMap = map[int]string{ 0: "Legacy Triangle", 1: "Rhythm", 2: "Square", 3: "Control Square Master", 4: "Control Square Passive", 7: "Hexagon", 8: "Triangle", 9: "Mini Triangle", 12: "Shapes Controller", 15: "Element Corner", }
var shapeIconMap = map[int]string{ 0: "shape_triangle", 1: "shape_triangle", 2: "shape_square", 3: "shape_square", 4: "shape_square", 7: "shape_hexagon", 8: "shape_triangle", 9: "shape_triangle", 12: "shape_hexagon", 15: "shape_hexagon_corner", }
var shapeWidthMap = map[int]int{ 0: 150, 1: -1, 2: 100, 3: 100, 4: 100, 7: 67, 8: 134, 9: 67, 12: -1, }
var httpMessage = []byte(`{ "write": { "command": "display", "animType": "extControl", "extControlVersion": "v2" }}`)
type panel struct { ID uint16 FullID string
On bool Intensity float64 ColorRGBA [4]byte TransitionAt time.Time
O int X int Y int ShapeType int
Stale bool SlowUpdates int TicksUntilSlowUpdate int }
func (p *panel) message() (message [8]byte) { transitionTime := p.TransitionAt.Sub(time.Now()).Round(time.Millisecond * 100) if transitionTime > maxTransitionTime { transitionTime = maxTransitionTime } else if transitionTime < 0 { transitionTime = 0 }
binary.BigEndian.PutUint16(message[0:], p.ID) copy(message[2:], p.ColorRGBA[:]) binary.BigEndian.PutUint16(message[6:], uint16(transitionTime/(time.Millisecond*100)))
return }
func (p *panel) update(colorRGBA [4]byte, transitionAt time.Time) { if p.ColorRGBA != colorRGBA { p.ColorRGBA = colorRGBA p.Stale = true p.SlowUpdates = 3 p.TicksUntilSlowUpdate = 10 } p.TransitionAt = transitionAt }
func (p *panel) apply(change device.State, transitionTime time.Time) { if change.Power != nil { p.On = *change.Power }
if change.Intensity != nil { p.Intensity = *change.Intensity }
if change.Color == nil { change.Color = &color.Color{RGB: &color.RGB{Red: 255, Green: 255, Blue: 255}} }
if !p.On { newColor := [4]byte{0, 0, 0, 0} if newColor != p.ColorRGBA { p.update(newColor, transitionTime) } } else { rgbColor, ok := change.Color.ToRGB() if !ok { newColor := [4]byte{255, 255, 255, 255} if newColor != p.ColorRGBA { p.update(newColor, transitionTime) } }
rgb := rgbColor.RGB.AtIntensity(p.Intensity) red := byte(rgb.Red * 255.0001) green := byte(rgb.Green * 255.0001) blue := byte(rgb.Blue * 255.0001) newColor := [4]byte{red, green, blue, 255} if newColor != p.ColorRGBA { p.update(newColor, transitionTime) } } }
type panelUpdate []byte
func (u *panelUpdate) Add(message [8]byte) { if len(*u) < 2 { *u = make([]byte, 2, 10) }
binary.BigEndian.PutUint16(*u, binary.BigEndian.Uint16(*u)+1)
*u = append(*u, message[:]...) }
func (u *panelUpdate) Len() int { if len(*u) < 2 { return 0 }
return int(binary.BigEndian.Uint16(*u)) }
const maxTransitionTime = time.Minute * 109
|