Compare commits

..

4 Commits

4 changed files with 99 additions and 14 deletions

9
Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM scratch
COPY wemo /
COPY --chown=65534:65534 movieMode.json /tmp/
WORKDIR /tmp
USER 65534
EXPOSE 8081
ENTRYPOINT ["/wemo"]

View File

@ -429,10 +429,10 @@ FAUXMOS = [
[
'Movie Mode',
rest_api_handler(
'http://movielights:20000/basement?moviemode=true',
'http://movielights:20000/basement?moviemode=false'
'http://movielights:10000/basement?moviemode=true',
'http://movielights:10000/basement?moviemode=false'
),
20000
10000
],
]

View File

@ -7,19 +7,26 @@
"content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"><BinaryState>1</BinaryState><brightness>${val}</brightness></u:SetBinaryState></s:Body></s:Envelope>",
"steps": 15,
"seconds": 5,
"start": 100,
"start": -1,
"end": 20,
"endOff": true
"endOff": true,
"startAction": "\"urn:Belkin:service:basicevent:1#GetBinaryState\"",
"startContent": "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:GetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"></u:GetBinaryState></s:Body></s:Envelope>",
"startField": "brightness"
},
{
"device": "Bar",
"comment": "Bar lights down to 10%",
"comment": "Bar lights down to 10%, then off",
"action": "\"urn:Belkin:service:basicevent:1#SetBinaryState\"",
"content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"><BinaryState>1</BinaryState><brightness>${val}</brightness></u:SetBinaryState></s:Body></s:Envelope>",
"steps": 15,
"seconds": 5,
"start": 100,
"end": 0
"start": -1,
"end": 0,
"endOff": true,
"startAction": "\"urn:Belkin:service:basicevent:1#GetBinaryState\"",
"startContent": "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:GetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"></u:GetBinaryState></s:Body></s:Envelope>",
"startField": "brightness"
}
],
"off": [
@ -31,7 +38,7 @@
"steps": 15,
"seconds": 5,
"start": 20,
"end": 100
"end": 60
},
{
"device": "Bar",

79
wemo.go
View File

@ -3,6 +3,7 @@ package main
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"log"
@ -17,6 +18,7 @@ import (
"git.lerch.org/lobo/wemo/wemodiscovery"
)
type basementPost struct {
MovieMode bool
}
@ -31,6 +33,7 @@ type controlData struct {
type deviceAction struct {
Device, Action, Content string
StartAction, StartContent, StartField string
Steps, Seconds, Start, End int
EndOff bool
}
@ -39,10 +42,28 @@ type soapActions struct {
On, Off []deviceAction
}
type soapResponse struct {
XMLName xml.Name `xml:"Envelope"`
Body getBinaryStateBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type getBinaryStateBody struct {
XMLName xml.Name
GetBinaryStateResponse getBinaryStateBodyResponse `xml:"urn:Belkin:service:basicevent:1 GetBinaryStateResponse"`
}
type getBinaryStateBodyResponse struct {
XMLName xml.Name
State bool `xml:"BinaryState"`
Brightness int `xml:"brightness"`
Fader string `xml:"fader"`
}
var command string
var client http.Client
func main() {
getState := "\"urn:Belkin:service:basicevent:1#GetBinaryState\""
getStateContent := "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:GetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"></u:GetBinaryState></s:Body></s:Envelope>"
command = os.Getenv("CMD")
port := os.Getenv("PORT")
if port == "" { port = ":8081" } else { port = ":" + port }
@ -50,10 +71,25 @@ func main() {
if len(os.Args) > 1 {
if os.Args[1] == "on" {
movieMode(true)
}else{
time.Sleep(10 * time.Second) // Allow the thread time to do magic
}else if os.Args[1] == "off" {
movieMode(false)
time.Sleep(10 * time.Second) // Allow the thread time to do magic
}else if os.Args[1] == "scan" {
refreshControl()
println("control file updated")
}else if os.Args[1] == "getState" {
logger.Infof("getState")
addresses := readAddresses()
for _, address := range addresses.Devices {
if address.Name == os.Args[2] {
dim := getCurrentDimValue(address.Url+addresses.BasicEvent, address.Name, getState, getStateContent)
println("dim value is ", dim)
}
}
}else{
println("wemo [on|off|scan|getState] [device name]")
}
time.Sleep(10 * time.Second)
// movieMode(false)
os.Exit(0)
}
@ -131,13 +167,17 @@ func commandDevice(url string, device deviceAction) {
sendCommand(url, device, device.Content)
return
}
logger.Tracef("%s: Stepping the change. %d to %d over %d steps", device.Device, device.Start, device.End, device.Steps)
start := device.Start
if start == -1 {
start = getCurrentDimValue(url, device.Device, device.StartAction, device.StartContent)
}
logger.Tracef("%s: Stepping the change. %d to %d over %d steps", device.Device, start, device.End, device.Steps)
// We want to fade something...
millisecondsPerTick := device.Seconds * 1000 / device.Steps
logger.Tracef("%s: %d ms per step over %d seconds", device.Device, millisecondsPerTick, device.Seconds)
deltaPerTick := (device.End - device.Start) / (device.Steps - 1)
deltaPerTick := (device.End - start) / (device.Steps - 1)
logger.Tracef("%s: %d change per command", device.Device, deltaPerTick)
currentValue := device.Start
currentValue := start
currentSteps := 0
ticker := time.NewTicker(time.Duration(millisecondsPerTick) * time.Millisecond)
quit := make(chan struct{})
@ -192,6 +232,35 @@ func sendCommand(url string, device deviceAction, content string) {
}
}
func getCurrentDimValue(url string, name string, action string, content string) int {
req, err := http.NewRequest("POST", url, nil)
rc := 0
if err != nil {
logger.Errorf("Error building http request to device %s: %s", name, err)
}
req.Header.Add("SOAPACTION", action)
req.Header.Add("Content-type", `text/xml; charset="utf-8"`)
req.Body = ioutil.NopCloser(bytes.NewBufferString(content))
res, err := client.Do(req)
if err != nil {
logger.Errorf("Error on http request to device %s: %s", name, err)
}else{
responseBytes, err := ioutil.ReadAll(res.Body)
logger.Tracef("%s: Response from lights: %s", name, responseBytes)
if err != nil {
logger.Errorf("Error reading response from device %s: %s", name, err)
}
var envelope soapResponse
xml.Unmarshal(responseBytes, &envelope)
rc = envelope.Body.GetBinaryStateResponse.Brightness
logger.Tracef("%s: Unmarshal: #v", name, envelope)
logger.Tracef("%s: Brightness: %d", name, rc)
logger.Tracef("%s: State: %t", name, envelope.Body.GetBinaryStateResponse.State)
logger.Tracef("%s: Fader: %s", name, envelope.Body.GetBinaryStateResponse.Fader)
}
return rc
}
func readAddresses() controlData {
var rc controlData
bytes, err := ioutil.ReadFile("controlData.json")