forked from nItroTools/sungrow-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sungrow.go
151 lines (127 loc) · 4.47 KB
/
sungrow.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"encoding/json"
"flag"
"log"
"maps"
"strings"
"time"
"github.com/sroeck/sungrow-go/mqtt"
"github.com/sroeck/sungrow-go/ws"
)
type InverterParams struct {
host string
port int
path string
data string
types []string
}
func main() {
inverterParams, mqttParams, sleepTimeInSeconds := flags()
log.Printf("Polling the inverter every %d seconds\n", sleepTimeInSeconds)
ticker := time.NewTicker(time.Duration(sleepTimeInSeconds) * time.Second)
done := make(chan bool)
defer ticker.Stop()
go func() {
// run immediately and then at the configured interval
fetchDataFromInverterAndSendToMqtt(inverterParams, mqttParams)
for {
select {
case <-done:
return
case <-ticker.C:
fetchDataFromInverterAndSendToMqtt(inverterParams, mqttParams)
}
}
}()
// block forever
select {}
}
func fetchDataFromInverterAndSendToMqtt(inverterParams *InverterParams, mqttParams *mqtt.MqttParams) {
webSocket := openWebSocket(inverterParams)
defer webSocket.Close()
var receivedValues map[string]any = make(map[string]any)
for _, t := range inverterParams.types {
switch t {
case "pv":
log.Println("Fetching pv data")
pvValues, err := webSocket.Pv()
processWsResult(receivedValues, pvValues, err)
case "battery":
log.Println("Fetching battery data")
batteryValues, err := webSocket.Battery()
processWsResult(receivedValues, batteryValues, err)
}
}
if len(receivedValues) == 0 {
log.Println("Skip sending MQTT data as no data have been returned from inverter")
return
}
mqtt.Send(mqttParams, receivedValues)
}
func processWsResult(targetMap map[string]any, resultMap map[string]any, err error) {
if err != nil {
log.Fatalln(err)
return
}
if len(resultMap) == 0 {
log.Println("Warning: No data returned")
return
}
prettyPrintMap(resultMap)
maps.Copy(targetMap, resultMap)
}
func prettyPrintMap(resultMap map[string]any) {
b, _ := json.MarshalIndent(resultMap, "", " ")
log.Print("Received the following values: ", string(b))
}
func openWebSocket(inverterParams *InverterParams) *ws.WS {
webSocket := ws.NewWS(inverterParams.host, inverterParams.port, inverterParams.path)
if err := webSocket.Connect(); err != nil {
log.Fatalln(err)
}
return webSocket
}
// flags defines, parses and validates command-line flags from os.Args[1:]
func flags() (*InverterParams, *mqtt.MqttParams, int) {
host := flag.String("host", "", "Hostname/IP address of the Sungrow inverter")
port := flag.Int("port", 8082, "WebSocket port of the Sungrow inverter")
path := flag.String("path", "/ws/home/overview", "Server path from where data is requested")
data := flag.String("data", "pv,battery", "Select the data to be requested comma separated.\nPossible values are \"pv\" and \"battery\"")
mqttServer := flag.String("mqtt.server", "", "mqtt server incl. protocol, e.g. mqtt://localhost:1883. For TLS use ssl scheme, e.g. ssl://localhost:8883")
mqttUser := flag.String("mqtt.user", "", "mqtt user name")
mqttPassword := flag.String("mqtt.password", "", "mqtt password")
mqttClientId := flag.String("mqtt.clientId", "", "mqtt clientId that is used for publishing")
mqttTopic := flag.String("mqtt.topic", "topic", "mqtt topic to which the data are published")
sleepBetweenCalls := flag.Int("sleep", 10, "sleep time in seconds between inverter calls.")
flag.Parse()
inverterParams := &InverterParams{host: *host, port: *port, path: *path, data: *data}
mqttParams := &mqtt.MqttParams{Server: *mqttServer, ClientId: *mqttClientId, Topic: *mqttTopic, User: *mqttUser, Password: *mqttPassword}
// Validate flags
validateInverterFlags(inverterParams)
validateMqttFlags(mqttParams)
return inverterParams, mqttParams, *sleepBetweenCalls
}
// validateInverterFlags validates all flags
func validateInverterFlags(inverterParams *InverterParams) {
if inverterParams.host == "" {
log.Fatalln("Required parameter 'host' not set!\n'sungrow-go -help' lists available parameters.")
}
inverterParams.types = strings.Split(inverterParams.data, ",")
if len(inverterParams.types) < 1 {
log.Fatalln("Required parameter 'data' not set or invalid value!\n'sungrow-go -help' lists available parameters and values.")
}
for _, t := range inverterParams.types {
switch t {
case "pv":
case "battery":
default:
log.Fatalf("Invalid value \"%s\" for parameter 'data'!\n'sungrow-go -help' lists available parameters and values.\n", t)
}
}
}
func validateMqttFlags(params *mqtt.MqttParams) {
if params.Server == "" {
log.Fatalln("Missing parameter mqtt.server")
}
}