diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a9b8cc8b8adc93afbfcccdd83f1eda3751b92a0f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.config.json diff --git a/nipca-motion/.local/options.json b/nipca-motion/.local/options.json deleted file mode 100644 index 4bbd7adecfe0216890ac1f472299fa504525b0d2..0000000000000000000000000000000000000000 --- a/nipca-motion/.local/options.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "log_level": "info", - "seconds_between_quotes": 5 -} diff --git a/nipca-motion/config.json b/nipca-motion/config.json index 2f62e6bc8c7a839c5df6c825b5efd44c0c2aa6b4..62e77f46ceac4ea9e57a118703fb1d7ff10db19e 100644 --- a/nipca-motion/config.json +++ b/nipca-motion/config.json @@ -1,6 +1,6 @@ { "name": "NIPCA Motion", - "version": "0.1", + "version": "0.3", "slug": "nipca-motion", "description": "Motion and sound sensors for NIPCA-compatible cameras", "url": "https://gitlab.hedenstroem.com/hassio/addons/nipca-motion", @@ -10,10 +10,14 @@ "arch": ["aarch64", "amd64", "armhf", "armv7", "i386"], "options": { "log_level": "info", - "seconds_between_quotes": 5 + "cameras": [ + { "url": "http://localhost", "username": "admin", "password": "password" } + ] }, "schema": { - "log_level": "list(trace|debug|info|notice|warning|error|fatal)", - "seconds_between_quotes": "int(1,120)" + "log_level": "list(trace|debug|info|warn|error|fatal|panic)", + "cameras": [ + { "url": "str", "username": "str", "password": "str" } + ] } } diff --git a/nipca-motion/src/go.mod b/nipca-motion/src/go.mod index 7e3e348fa329c79b81a24ca5ea9b89b5c8f52616..f79158f4e708769fd584ad4e6e66e8fe68f85dcb 100644 --- a/nipca-motion/src/go.mod +++ b/nipca-motion/src/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/davecgh/go-spew v1.1.1 + github.com/eclipse/paho.mqtt.golang v1.3.3 github.com/joho/godotenv v1.3.0 github.com/sirupsen/logrus v1.8.1 github.com/spf13/viper v1.7.1 diff --git a/nipca-motion/src/go.sum b/nipca-motion/src/go.sum index b19d44d9417ccfd95f97b286cd6c9570289f5094..5a0beb30761ca8a942301eb73fea5e564710ef96 100644 --- a/nipca-motion/src/go.sum +++ b/nipca-motion/src/go.sum @@ -36,6 +36,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/eclipse/paho.mqtt.golang v1.3.3 h1:Fh1zsLniMFJByLqKrSB9ZRjkbpU0k1Xne23ZqEE/O08= +github.com/eclipse/paho.mqtt.golang v1.3.3/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -67,6 +69,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -219,6 +222,8 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -240,8 +245,9 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= diff --git a/nipca-motion/src/main.go b/nipca-motion/src/main.go index bfc17adcdeacc5da0e90a91bc8c8e8a7b08a388d..fdb2867451d29f1ae5c83048fdd09e63cd452eaf 100644 --- a/nipca-motion/src/main.go +++ b/nipca-motion/src/main.go @@ -2,58 +2,168 @@ package main import ( "encoding/json" + "errors" "fmt" "io/ioutil" "net/http" + "time" - "github.com/davecgh/go-spew/spew" + mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/joho/godotenv" "github.com/sirupsen/logrus" "github.com/spf13/viper" ) +type MqttConfiguration struct { + Host string `json:"host"` + Port int `json:"port"` + SSL bool `json:"ssl"` + Protocol string `json:"protocol"` + Username string `json:"username"` + Password string `json:"password"` + Addon string `json:"addon"` + ClientID string `mapstructure:"client_id"` + DiscoveryPrefix string `mapstructure:"discovery_prefix"` +} + +type MqttService struct { + Result string `json:"result"` + Message string `json:"message"` + Config MqttConfiguration `json:"data"` +} + var log *logrus.Logger +type MqttLogger struct { + level logrus.Level +} + +func (logger MqttLogger) Println(args ...interface{}) { + log.Log(logger.level, args) +} + +func (logger MqttLogger) Printf(format string, args ...interface{}) { + log.Logf(logger.level, format, args) +} + func loadOptions() { godotenv.Load() viper.AutomaticEnv() - viper.SetConfigName("options") + viper.BindEnv("host", "MQTT_HOST") + viper.BindEnv("port", "MQTT_PORT") + viper.BindEnv("ssl", "MQTT_SSL") + viper.BindEnv("username", "MQTT_USERNAME") + viper.BindEnv("password", "MQTT_PASSWORD") + viper.BindEnv("client_id", "HOSTNAME") + viper.BindEnv("discovery_prefix", "MQTT_DISCOVERY_PREFIX") + viper.RegisterAlias("token", "SUPERVISOR_TOKEN") + viper.SetDefault("log_level", "info") + viper.SetDefault("discovery_prefix", "homeassistant") + viper.SetDefault("config_path", "/data") + viper.SetDefault("config_name", "options") + viper.AddConfigPath(viper.GetString("config_path")) + viper.SetConfigName(viper.GetString("config_name")) viper.SetConfigType("json") - viper.AddConfigPath("/data") if err := viper.ReadInConfig(); err != nil { - log.Fatal(err) + log.Warn(err) + } + if viper.GetString("log_level") == "debug" { + viper.Debug() } - viper.Debug() } -func getMQTTServiceInfo() ([]byte, error) { +func getMqttConfiguration() (MqttConfiguration, error) { + + service := MqttService{} + viper.Unmarshal(&service.Config) - client := &http.Client{} + token := viper.GetString("token") + if token == "" { + return service.Config, nil + } + + client := &http.Client{ + Timeout: time.Second * 10, + } req, err := http.NewRequest("GET", "http://supervisor/services/mqtt", nil) if err != nil { - return nil, err + return service.Config, err } - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", viper.GetString("SUPERVISOR_TOKEN"))) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) res, err := client.Do(req) if err != nil { - return nil, err + return service.Config, err } defer res.Body.Close() - return ioutil.ReadAll(res.Body) + bytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return service.Config, err + } + + err = json.Unmarshal(bytes, &service) + + if service.Result == "error" { + return service.Config, errors.New("MQTT Configuration: " + service.Message) + } + + return service.Config, err + +} + +func openMqttConnection(config MqttConfiguration) (mqtt.Client, error) { + scheme := "tcp" + if config.SSL { + scheme = "ssl" + } + broker := fmt.Sprintf("%s://%s:%d", scheme, config.Host, config.Port) + availabilityTopic := fmt.Sprintf("%s/addon/nipca-motion/availability", config.DiscoveryPrefix) + opts := mqtt.NewClientOptions() + opts.AddBroker(broker).SetClientID(config.ClientID) + opts.SetWill(availabilityTopic, "offline", 1, true) + opts.SetUsername(config.Username).SetPassword(config.Password) + client := mqtt.NewClient(opts) + token := client.Connect() + token.Wait() + err := token.Error() + if err != nil { + return nil, err + } + token = client.Publish(availabilityTopic, 1, true, "online") + token.Wait() + err = token.Error() + if err != nil { + return nil, err + } + return client, nil } func main() { + log = logrus.New() loadOptions() - log.Info(viper.GetString("SUPERVISOR_TOKEN")) - b, err := getMQTTServiceInfo() + level, err := logrus.ParseLevel(viper.GetString("log_level")) + if err == nil { + log.SetLevel(level) + } + log.Info("Log level: ", level) + mqtt.ERROR = MqttLogger{level: logrus.ErrorLevel} + mqtt.CRITICAL = MqttLogger{level: logrus.ErrorLevel} + mqtt.WARN = MqttLogger{level: logrus.WarnLevel} + mqtt.DEBUG = MqttLogger{level: logrus.DebugLevel} + + mqttConfig, err := getMqttConfiguration() if err != nil { log.Fatal(err) } - var result map[string]interface{} - json.Unmarshal(b, &result) - spew.Dump(result) + log.Debugf("MQTT Config: %+v", mqttConfig) + + mqttClient, err := openMqttConnection(mqttConfig) + if err != nil { + log.Fatal(err) + } + mqttClient.IsConnected() + } diff --git a/nipca-motion/src/meh.txt b/nipca-motion/src/meh.txt deleted file mode 100644 index 51b4f0db5cc2242d5a4aa6e50d333d9ceceee7f1..0000000000000000000000000000000000000000 --- a/nipca-motion/src/meh.txt +++ /dev/null @@ -1,40 +0,0 @@ -Aliases: -map[string]string{} -Override: -map[string]interface {}{} -PFlags: -map[string]viper.FlagValue{} -Env: -map[string]string{} -Key/Value Store: -map[string]interface {}{} -Config: -map[string]interface {}{"log_level":"info", "seconds_between_quotes":5} -Defaults: -map[string]interface {}{} -time="2021-04-23T16:37:55Z" level=info msg=da4196cd1ed12cfd51071d76a0276f1a3fed222eae2be5c68c9f64e1e6fe15d59b47801604ce89a613e600125fca41e5c90de092e1099fd0 -{"result": "error", "message": "Service not enabled"} - -Aliases: -map[string]string{} -Override: -map[string]interface {}{} -PFlags: -map[string]viper.FlagValue{} -Env: -map[string]string{} -Key/Value Store: -map[string]interface {}{} -Config: -map[string]interface {}{"log_level":"info", "seconds_between_quotes":5} -Defaults: -map[string]interface {}{} -time="2021-04-23T16:39:25Z" level=info msg=329015baa110284c7f112774caa3b0c5186bc00449bc5d77e93411cf7752ffdbeaec80a2c9a85d608e3138996a0df2fea7cde3f380c349bd -{"result": "ok", "data": {"host": "core-mosquitto", "port": 1883, "ssl": false, "protocol": "3.1.1", "username": "addons", "password": "aehoh5usheiba3auNgai1aa6yai9Pheizaepei4teiTh2aaD0GieTheit4paefi2", "addon": "core_mosquitto"}} - - -8d5a09c8e1e0410e8b721f85bbf9adfd - - "--cap-add=SYS_PTRACE", - "--security-opt", - "seccomp=unconfined",