Created
December 16, 2016 11:10
-
-
Save DanyHenriquez/e12b88db436efb043283f6af2a5c5624 to your computer and use it in GitHub Desktop.
Ambihue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"log" | |
"fmt" | |
"time" | |
"runtime" | |
"os" | |
"github.com/BurntSushi/xgb/xproto" | |
"github.com/BurntSushi/xgbutil" | |
"github.com/BurntSushi/xgbutil/xgraphics" | |
"github.com/go-resty/resty" | |
"github.com/lucasb-eyer/go-colorful" | |
"github.com/BurntSushi/toml" | |
"github.com/tidwall/gjson" | |
"sync" | |
) | |
type Configuration struct { | |
BridgeAddress string | |
User string | |
Top int | |
Right int | |
Bottom int | |
Left int | |
DimLights []int | |
DimValue int | |
TransitionTime int | |
BrightnessCorrection int | |
SignalInterval int | |
} | |
type LightState struct { | |
number int | |
state string | |
} | |
func parseConfig(file string) (Configuration) { | |
var configuration Configuration | |
if _, err := toml.DecodeFile(file, &configuration); err != nil { | |
log.Fatal(err) | |
} | |
return configuration | |
} | |
func getLightStates(config Configuration) ([]LightState) { | |
lightStates := make([]LightState, len(config.DimLights) + 4) | |
r, _ := resty.R().Get(fmt.Sprintf("http://%s/api/%s/lights/%d", config.BridgeAddress, config.User, config.Top)) | |
value := gjson.Get(string(r.Body()), "state.*") | |
lightStates = append(lightStates, LightState{number: config.Top, state: value.String()}) | |
r, _ = resty.R().Get(fmt.Sprintf("http://%s/api/%s/lights/%d", config.BridgeAddress, config.User, config.Right)) | |
value = gjson.Get(string(r.Body()), "state.*") | |
lightStates = append(lightStates, LightState{number: config.Right, state: value.String()}) | |
r, _ = resty.R().Get(fmt.Sprintf("http://%s/api/%s/lights/%d", config.BridgeAddress, config.User, config.Bottom)) | |
value = gjson.Get(string(r.Body()), "state.*") | |
lightStates = append(lightStates, LightState{number: config.Bottom, state: value.String()}) | |
r, _ = resty.R().Get(fmt.Sprintf("http://%s/api/%s/lights/%d", config.BridgeAddress, config.User, config.Left)) | |
value = gjson.Get(string(r.Body()), "state.*") | |
lightStates = append(lightStates, LightState{number: config.Left, state: value.String()}) | |
for _, light := range config.DimLights { | |
r, _ = resty.R().Get(fmt.Sprintf("http://%s/api/%s/lights/%d", config.BridgeAddress, config.User, light)) | |
value = gjson.Get(string(r.Body()), "state.*") | |
lightStates = append(lightStates, LightState{number: light, state: value.String()}) | |
} | |
return lightStates | |
} | |
func restoreState(lightStates []LightState, config Configuration) { | |
for _, light := range lightStates { | |
resty.R(). | |
SetBody(light.state). | |
Put(fmt.Sprintf("http://%s/api/%s/lights/%d", config.BridgeAddress, config.User, light.number)) | |
} | |
} | |
func changeState(ximg *xgraphics.Image, light int, XCoordinate int, YCoordinate int, config Configuration) { | |
R, G, B, _ := ximg.At(XCoordinate, YCoordinate).RGBA() | |
c := colorful.Color{(1.0 / 65535.0) * float64(R), (1.0 / 65535.0) * float64(G), (1.0 / 65535.0) * float64(B)} | |
x, y, z := c.Xyz() | |
bri := int(1.0 / 254.0 * y) | |
body := fmt.Sprintf(`{"transitiontime": %d, "bri":%d,"xy": [%f, %f]}`, config.TransitionTime, bri + config.BrightnessCorrection, x / (x + y + z), y / (x + y + z)) | |
resty.R(). | |
SetHeader("Content-Type", "application/json"). | |
SetBody(body). | |
Put(fmt.Sprintf("http://%s/api/%s/lights/%d/state", config.BridgeAddress, config.User, light)) | |
} | |
func DimLights(config Configuration) { | |
for _, light := range config.DimLights { | |
go DimLight(light, config) | |
} | |
} | |
func DimLight(light int, config Configuration) { | |
body := fmt.Sprintf(`{"bri": %d}`, config.DimValue) | |
resty.R(). | |
SetHeader("Content-Type", "application/json"). | |
SetBody(body). | |
Put(fmt.Sprintf("http://%s/api/%s/lights/%d/state", config.BridgeAddress, config.User, light)) | |
} | |
func process(X *xgbutil.XUtil, config Configuration) { | |
ximg, err := xgraphics.NewDrawable(X, xproto.Drawable(X.RootWin())) | |
if err != nil { | |
log.Fatal(err) | |
} | |
var wg sync.WaitGroup | |
wg.Add(4) | |
if config.Top != 0 { | |
go changeState(ximg, config.Top, ximg.Bounds().Max.X / 2, ximg.Bounds().Min.Y + 100, config) | |
} | |
if config.Right != 0 { | |
go changeState(ximg, config.Right, ximg.Bounds().Max.X - 100, ximg.Bounds().Max.Y / 2, config) | |
} | |
if config.Bottom != 0 { | |
go changeState(ximg, config.Bottom, ximg.Bounds().Max.X / 2, ximg.Bounds().Max.Y - 100, config) | |
} | |
if config.Left != 0 { | |
go changeState(ximg, config.Left, ximg.Bounds().Min.X + 100, ximg.Bounds().Max.Y / 2, config) | |
} | |
} | |
func main() { | |
runtime.GOMAXPROCS(2) | |
config := parseConfig(os.Args[1]) | |
lightStates := getLightStates(config) | |
DimLights(config) | |
X, err := xgbutil.NewConn() | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer restoreState(lightStates, config) | |
for { | |
go process(X, config) | |
time.Sleep(time.Duration(config.SignalInterval) * time.Millisecond) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BridgeAddress = "<ip address>" | |
User = "<Bridge user>" | |
Top = 0 | |
Right = 2 | |
Bottom = 0 | |
Left = 1 | |
DimLights = [] | |
DimValue = 150 | |
TransitionTime = 4 | |
BrightnessCorrection = 200 | |
SignalInterval = 250 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment