Add configuration
Add yaml configuration file handling
This commit is contained in:
parent
cd8b6da112
commit
aea0620747
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1 +1,5 @@
|
||||||
|
# Binaries
|
||||||
/smartbridge
|
/smartbridge
|
||||||
|
|
||||||
|
# Config files
|
||||||
|
/*.yml
|
||||||
|
|
|
@ -1,13 +1,47 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Remote string // Remote IP address of the Smartbridge
|
Remote string `yaml:"remote"` // Remote IP address of the Smartbridge
|
||||||
Mqtt string // mqtt server
|
Mqtt MqttConfig `yaml:"mqtt"` // mqtt configuration
|
||||||
|
Delay int `yaml:"delay"`
|
||||||
|
Verbose bool `yaml:"verbose"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MqttConfig struct {
|
||||||
|
Remote string `yaml:"remote"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
ClientID string `yaml:"clientid"`
|
||||||
|
topic string `yaml:"topic"`
|
||||||
|
Username string `yaml:"username"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var cf Config
|
var cf Config
|
||||||
|
|
||||||
func (cf *Config) SetDefaults() {
|
func (cf *Config) SetDefaults() {
|
||||||
cf.Remote = "192.168.242.199"
|
cf.Remote = "127.0.0.1"
|
||||||
cf.Mqtt = "192.168.0.42"
|
cf.Delay = 5
|
||||||
|
cf.Mqtt.Remote = "127.0.0.1"
|
||||||
|
cf.Mqtt.Port = 1883
|
||||||
|
cf.Mqtt.ClientID = "smartbridge"
|
||||||
|
cf.Mqtt.topic = "home/power"
|
||||||
|
cf.Mqtt.Username = ""
|
||||||
|
cf.Mqtt.Password = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cf *Config) LoadYAML(filename string) error {
|
||||||
|
content, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := yaml.Unmarshal(content, cf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,25 +10,9 @@ import (
|
||||||
|
|
||||||
var mqtt_c Mqtt
|
var mqtt_c Mqtt
|
||||||
|
|
||||||
func establishMqtt() error {
|
func registerTerminationSignal() {
|
||||||
var err error
|
|
||||||
n := 5 // Reconnection attempts
|
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
mqtt_c, err = ConnectMqtt(cf.Mqtt, 1883)
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "mqtt error: %s (attempt %d/%d)\n", err, i+1, n)
|
|
||||||
time.Sleep(time.Second * time.Duration(i))
|
|
||||||
}
|
|
||||||
return fmt.Errorf("connection failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// awaits SIGINT or SIGTERM and quit program
|
|
||||||
func awaitTerminationSignal() {
|
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGABRT)
|
||||||
go func() {
|
go func() {
|
||||||
sig := <-sigs
|
sig := <-sigs
|
||||||
fmt.Println(sig)
|
fmt.Println(sig)
|
||||||
|
@ -36,15 +20,39 @@ func awaitTerminationSignal() {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func loadConfig(filename string) {
|
||||||
cf.SetDefaults()
|
if !fileExists(filename) {
|
||||||
|
return
|
||||||
if err := establishMqtt(); err != nil {
|
}
|
||||||
fmt.Fprintf(os.Stderr, "mqtt: %s\n", err)
|
if err := cf.LoadYAML(filename); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error loading configuration '%s': %s\n", filename, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
awaitTerminationSignal()
|
func main() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
cf.SetDefaults()
|
||||||
|
// Try to load default locations
|
||||||
|
loadConfig("/etc/smartbridge.yml")
|
||||||
|
loadConfig("./smartbridge.yml")
|
||||||
|
// Program arguments are configuration files
|
||||||
|
for i := 1; i < len(os.Args); i++ {
|
||||||
|
arg := os.Args[i]
|
||||||
|
if err := cf.LoadYAML(arg); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error loading configuration '%s': %s\n", arg, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mqtt_c, err = ConnectMqtt(cf.Mqtt)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "mqtt error: %s\n", err)
|
||||||
|
os.Exit(101)
|
||||||
|
}
|
||||||
|
|
||||||
|
registerTerminationSignal()
|
||||||
fmt.Println("smartbridge SBWF3102 reader")
|
fmt.Println("smartbridge SBWF3102 reader")
|
||||||
for true {
|
for true {
|
||||||
reading, err := ReadSmartbridge(cf.Remote)
|
reading, err := ReadSmartbridge(cf.Remote)
|
||||||
|
@ -54,7 +62,12 @@ func main() {
|
||||||
if reading.Status != "ok" {
|
if reading.Status != "ok" {
|
||||||
fmt.Fprintf(os.Stderr, "status: %s\n", reading.Status)
|
fmt.Fprintf(os.Stderr, "status: %s\n", reading.Status)
|
||||||
} else {
|
} else {
|
||||||
data := fmt.Sprintf("{\"power\":%d,\"unit\":\"W\",\"timestamp\":%d}", reading.Electricity.Power.Current.Value, time.Now().Unix())
|
data := fmt.Sprintf("{\"power\":%d,\"unit\":\"W\",\"min\":%d,\"max\":%d,\"timestamp\":%d}", reading.Electricity.Power.Current.Value, reading.Electricity.Power.Minimun.Value, reading.Electricity.Power.Maximum.Value, time.Now().Unix())
|
||||||
|
if cf.Verbose {
|
||||||
|
fmt.Print(cf.Mqtt.topic)
|
||||||
|
fmt.Print(" ")
|
||||||
|
fmt.Println(data)
|
||||||
|
}
|
||||||
mqtt_c.Publish("home/power", data)
|
mqtt_c.Publish("home/power", data)
|
||||||
}
|
}
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
|
|
|
@ -10,13 +10,19 @@ type Mqtt struct {
|
||||||
client mqtt.Client
|
client mqtt.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectMqtt(broker string, port int) (Mqtt, error) {
|
func ConnectMqtt(cf MqttConfig) (Mqtt, error) {
|
||||||
var ret Mqtt
|
var ret Mqtt
|
||||||
opts := mqtt.NewClientOptions()
|
opts := mqtt.NewClientOptions()
|
||||||
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
|
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", cf.Remote, cf.Port))
|
||||||
opts.SetClientID("smartbridge")
|
if cf.ClientID != "" {
|
||||||
//opts.SetUsername("emqx")
|
opts.SetClientID(cf.ClientID)
|
||||||
//opts.SetPassword("public")
|
}
|
||||||
|
if cf.Username != "" {
|
||||||
|
opts.SetUsername(cf.Username)
|
||||||
|
}
|
||||||
|
if cf.Password != "" {
|
||||||
|
opts.SetPassword(cf.Password)
|
||||||
|
}
|
||||||
//opts.SetDefaultPublishHandler(messagePubHandler)
|
//opts.SetDefaultPublishHandler(messagePubHandler)
|
||||||
//opts.OnConnect = connectHandler
|
//opts.OnConnect = connectHandler
|
||||||
//opts.OnConnectionLost = connectLostHandler
|
//opts.OnConnectionLost = connectLostHandler
|
||||||
|
|
11
cmd/smartbridge/utils.go
Normal file
11
cmd/smartbridge/utils.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func fileExists(filename string) bool {
|
||||||
|
info, err := os.Stat(filename)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !info.IsDir()
|
||||||
|
}
|
5
go.mod
5
go.mod
|
@ -2,7 +2,10 @@ module feldspaten.org/smartbridge/v2
|
||||||
|
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require github.com/eclipse/paho.mqtt.golang v1.4.2
|
require (
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.4.2
|
||||||
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gorilla/websocket v1.4.2 // indirect
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -10,3 +10,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
|
11
smartbridge.service
Normal file
11
smartbridge.service
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=smartbridge reader service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=nobody
|
||||||
|
#WorkingDirectory=/var/empty
|
||||||
|
ExecStart=/usr/bin/smartbridge
|
||||||
|
Restart=always
|
||||||
|
RestartSec=30
|
14
smartbridge.yml.example
Normal file
14
smartbridge.yml.example
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
# smartbridge configuration
|
||||||
|
|
||||||
|
remote: "192.168.0.1" # Smartbridge IP address
|
||||||
|
delay: 5 # Seconds between polls
|
||||||
|
verbose: False
|
||||||
|
|
||||||
|
mqtt:
|
||||||
|
remote: "192.168.0.1"
|
||||||
|
port: 1883
|
||||||
|
clientid: "smartbridge"
|
||||||
|
topic: "home/power"
|
||||||
|
username: ""
|
||||||
|
password: ""
|
Loading…
Reference in a new issue