First commit
This commit is contained in:
commit
d140fd8953
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/mqtt-backlight-control
|
||||
/mqtt-backlight-control.exe
|
||||
/.vscode
|
61
README.md
Normal file
61
README.md
Normal file
@ -0,0 +1,61 @@
|
||||
# MQTT backlight control
|
||||
|
||||
Simple mqtt command executor to turn screen on or off via MQTT.
|
||||
|
||||
Config example:
|
||||
|
||||
```yaml
|
||||
mqtt:
|
||||
address: "tcp://example.com:1883"
|
||||
username: "mqtt"
|
||||
password: "${MQTT_PASSWORD}"
|
||||
command_topic: "light/screen/command"
|
||||
state_topic: "light/screen/state"
|
||||
commands:
|
||||
on:
|
||||
program: "xrandr"
|
||||
args:
|
||||
- "--display"
|
||||
- ":0"
|
||||
- "--output"
|
||||
- "HDMI-0"
|
||||
- "--auto"
|
||||
off:
|
||||
program: "xrandr"
|
||||
args:
|
||||
- "--display"
|
||||
- ":0"
|
||||
- "--output"
|
||||
- "HDMI-0"
|
||||
- "--off"
|
||||
```
|
||||
|
||||
Password is provided via **MQTT_PASSWORD** environment variable.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
mqtt-backlight-control config.yaml
|
||||
```
|
||||
|
||||
Systemd unit example:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Control screen backlight via mqtt
|
||||
After=network-online.target
|
||||
StartLimitIntervalSec=500
|
||||
StartLimitBurst=5
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=mqtt_backlight_control
|
||||
Environment=MQTT_PASSWORD=xxxxxxxxxxxxx
|
||||
WorkingDirectory=/opt/backlight-control/
|
||||
ExecStart=/opt/backlight-control/mqtt-backlight-control config.yaml
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
11
go.mod
Normal file
11
go.mod
Normal file
@ -0,0 +1,11 @@
|
||||
module mqtt-backlight-control
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
11
go.sum
Normal file
11
go.sum
Normal file
@ -0,0 +1,11 @@
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
115
main.go
Normal file
115
main.go
Normal file
@ -0,0 +1,115 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var config = Config{}
|
||||
|
||||
type MqttConfig struct {
|
||||
Address string
|
||||
Username string
|
||||
Password string
|
||||
CommandTopic string `yaml:"command_topic"`
|
||||
StateTopic string `yaml:"state_topic"`
|
||||
}
|
||||
|
||||
type CommandDef struct {
|
||||
Program string
|
||||
Args []string `yaml:",flow"`
|
||||
}
|
||||
|
||||
type CommandConfig struct {
|
||||
On CommandDef
|
||||
Off CommandDef
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Mqtt MqttConfig
|
||||
Commands CommandConfig
|
||||
}
|
||||
|
||||
var onCommandMessage mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
|
||||
value := string(msg.Payload())
|
||||
fmt.Println(value)
|
||||
|
||||
var cmd *exec.Cmd
|
||||
|
||||
if value == "ON" {
|
||||
cmd = exec.Command(config.Commands.On.Program, config.Commands.On.Args...)
|
||||
} else {
|
||||
cmd = exec.Command(config.Commands.Off.Program, config.Commands.Off.Args...)
|
||||
}
|
||||
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Execution error: %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// fmt.Printf("Command output: %v\n", string(stdout))
|
||||
|
||||
token := client.Publish(config.Mqtt.StateTopic, 0, false, value)
|
||||
token.Wait()
|
||||
}
|
||||
|
||||
var onConnected mqtt.OnConnectHandler = func(client mqtt.Client) {
|
||||
fmt.Println("Connected")
|
||||
|
||||
token := client.Subscribe(config.Mqtt.CommandTopic, 1, onCommandMessage)
|
||||
token.Wait()
|
||||
}
|
||||
|
||||
var onDisconnected mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
|
||||
fmt.Fprintf(os.Stderr, "Connection lost: %v\n", err)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s config.yaml\n", os.Args[0])
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
yamlData, err := os.ReadFile(os.Args[1])
|
||||
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
yamlStr := os.ExpandEnv(string(yamlData))
|
||||
err = yaml.Unmarshal([]byte(yamlStr), &config)
|
||||
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
opts := mqtt.NewClientOptions()
|
||||
opts.AddBroker(config.Mqtt.Address)
|
||||
opts.SetClientID("screen_backlight_listener")
|
||||
opts.SetUsername(config.Mqtt.Username)
|
||||
opts.SetPassword(config.Mqtt.Password)
|
||||
opts.SetAutoReconnect(true)
|
||||
|
||||
opts.OnConnect = onConnected
|
||||
opts.OnConnectionLost = onDisconnected
|
||||
client := mqtt.NewClient(opts)
|
||||
|
||||
if token := client.Connect(); token.Wait() && token.Error() != nil {
|
||||
panic(token.Error())
|
||||
}
|
||||
|
||||
// wait forever for interrupt
|
||||
exit := make(chan os.Signal, 1)
|
||||
defer close(exit)
|
||||
signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-exit
|
||||
|
||||
client.Disconnect(250)
|
||||
}
|
Loading…
Reference in New Issue
Block a user