mirror of
https://github.com/MickMake/GoSungrow.git
synced 2025-06-06 21:19:31 +02:00
v2.2.0 MQTT changes
This commit is contained in:
parent
a639d2948f
commit
d57a1537db
114
.idea/workspace.xml
generated
114
.idea/workspace.xml
generated
@ -5,15 +5,21 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="76adadc9-ae71-42a6-82a1-66dbc8ecb14c" name="Changes" comment="">
|
<list default="true" id="76adadc9-ae71-42a6-82a1-66dbc8ecb14c" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/GoSungrow.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/GoSungrow.iml" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/HA/CHANGELOG.md" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/cmd/cmd_mqtt.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/cmd_mqtt.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/HA/Dockerfile" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/cmd/struct.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/struct.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/HA/GoSungrow" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/getPsDetailWithPsType/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/getPsDetailWithPsType/data.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/HA/build.yaml" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/getPsList/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/getPsList/data.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/HA/config.yaml" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceList/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceList/data.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/HA/src/GoSungrow" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/struct_points.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/struct_points.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/HA/src/run.sh" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/iSolarCloud/highlevel.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/highlevel.go" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/mmMqtt/config.go" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/mmMqtt/cron.go" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/mmMqtt/funcs.go" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/mmMqtt/lights.go" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/mmMqtt/sensors.go" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/mmMqtt/struct.go" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/mmMqtt/switch.go" beforeDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@ -79,7 +85,7 @@
|
|||||||
<configuration name="GoSungrow" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
<configuration name="GoSungrow" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||||
<module name="GoSungrow" />
|
<module name="GoSungrow" />
|
||||||
<working_directory value="$PROJECT_DIR$" />
|
<working_directory value="$PROJECT_DIR$" />
|
||||||
<parameters value="data get template 8092 20220301" />
|
<parameters value="mqtt run" />
|
||||||
<kind value="PACKAGE" />
|
<kind value="PACKAGE" />
|
||||||
<package value="$PROJECT_DIR$" />
|
<package value="$PROJECT_DIR$" />
|
||||||
<directory value="$PROJECT_DIR$" />
|
<directory value="$PROJECT_DIR$" />
|
||||||
@ -87,6 +93,23 @@
|
|||||||
<output_directory value="$PROJECT_DIR$/bin" />
|
<output_directory value="$PROJECT_DIR$/bin" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<configuration default="true" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||||
|
<module name="GoSungrow" />
|
||||||
|
<working_directory value="$PROJECT_DIR$" />
|
||||||
|
<kind value="FILE" />
|
||||||
|
<directory value="$PROJECT_DIR$" />
|
||||||
|
<filePath value="$PROJECT_DIR$" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="GoTestRunConfiguration" factoryName="Go Test">
|
||||||
|
<module name="GoSungrow" />
|
||||||
|
<working_directory value="$PROJECT_DIR$" />
|
||||||
|
<kind value="DIRECTORY" />
|
||||||
|
<directory value="$PROJECT_DIR$" />
|
||||||
|
<filePath value="$PROJECT_DIR$" />
|
||||||
|
<framework value="gotest" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@ -165,12 +188,12 @@
|
|||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
<line>207</line>
|
<line>232</line>
|
||||||
<option name="timeStamp" value="437" />
|
<option name="timeStamp" value="437" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
<line>206</line>
|
<line>231</line>
|
||||||
<option name="timeStamp" value="446" />
|
<option name="timeStamp" value="446" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
@ -190,27 +213,12 @@
|
|||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
<url>file://$PROJECT_DIR$/iSolarCloud/api/struct_points.go</url>
|
<url>file://$PROJECT_DIR$/iSolarCloud/api/struct_points.go</url>
|
||||||
<line>288</line>
|
<line>289</line>
|
||||||
<option name="timeStamp" value="523" />
|
<option name="timeStamp" value="523" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
|
||||||
<url>file://$PROJECT_DIR$/iSolarCloud/api/struct_points.go</url>
|
|
||||||
<line>309</line>
|
|
||||||
<option name="timeStamp" value="529" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
|
||||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
|
||||||
<line>138</line>
|
|
||||||
<option name="timeStamp" value="562" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
|
||||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
|
||||||
<line>234</line>
|
|
||||||
<option name="timeStamp" value="564" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||||
<line>492</line>
|
<line>518</line>
|
||||||
<option name="timeStamp" value="570" />
|
<option name="timeStamp" value="570" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
@ -223,16 +231,6 @@
|
|||||||
<line>136</line>
|
<line>136</line>
|
||||||
<option name="timeStamp" value="581" />
|
<option name="timeStamp" value="581" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
|
||||||
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceList/data.go</url>
|
|
||||||
<line>485</line>
|
|
||||||
<option name="timeStamp" value="586" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
|
||||||
<url>file://$PROJECT_DIR$/iSolarCloud/api/web.go</url>
|
|
||||||
<line>58</line>
|
|
||||||
<option name="timeStamp" value="589" />
|
|
||||||
</line-breakpoint>
|
|
||||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||||
<line>79</line>
|
<line>79</line>
|
||||||
@ -243,6 +241,46 @@
|
|||||||
<line>75</line>
|
<line>75</line>
|
||||||
<option name="timeStamp" value="593" />
|
<option name="timeStamp" value="593" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||||
|
<line>658</line>
|
||||||
|
<option name="timeStamp" value="619" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/mmHa/struct.go</url>
|
||||||
|
<line>395</line>
|
||||||
|
<option name="timeStamp" value="622" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
|
<line>263</line>
|
||||||
|
<option name="timeStamp" value="623" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
|
<line>268</line>
|
||||||
|
<option name="timeStamp" value="624" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
|
<line>269</line>
|
||||||
|
<option name="timeStamp" value="625" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
|
<line>264</line>
|
||||||
|
<option name="timeStamp" value="660" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
|
<line>273</line>
|
||||||
|
<option name="timeStamp" value="668" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||||
|
<line>295</line>
|
||||||
|
<option name="timeStamp" value="670" />
|
||||||
|
</line-breakpoint>
|
||||||
</breakpoints>
|
</breakpoints>
|
||||||
</breakpoint-manager>
|
</breakpoint-manager>
|
||||||
<watches-manager>
|
<watches-manager>
|
||||||
|
207
cmd/cmd_mqtt.go
207
cmd/cmd_mqtt.go
@ -2,11 +2,12 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"GoSungrow/Only"
|
"GoSungrow/Only"
|
||||||
"GoSungrow/mmMqtt"
|
"GoSungrow/mmHa"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-co-op/gocron"
|
"github.com/go-co-op/gocron"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -70,8 +71,33 @@ func (ca *CommandArgs) MqttArgs(cmd *cobra.Command, args []string) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogPrintDate("Connecting to SunGrow...\n")
|
||||||
|
Cmd.Error = Cmd.SunGrowArgs(cmd, args)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int64
|
||||||
|
id, Cmd.Error = Cmd.SunGrow.GetPsId()
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var model string
|
||||||
|
model, Cmd.Error = Cmd.SunGrow.GetPsModel()
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var serial string
|
||||||
|
serial, Cmd.Error = Cmd.SunGrow.GetPsSerial()
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
LogPrintDate("Found SunGrow device %s id:%d serial:%s\n", model, id, serial)
|
||||||
|
|
||||||
LogPrintDate("Connecting to MQTT HASSIO Service...\n")
|
LogPrintDate("Connecting to MQTT HASSIO Service...\n")
|
||||||
Cmd.Mqtt = mmMqtt.New(mmMqtt.Mqtt {
|
Cmd.Mqtt = mmHa.New(mmHa.Mqtt {
|
||||||
ClientId: "GoSunGrow",
|
ClientId: "GoSunGrow",
|
||||||
Username: Cmd.MqttUsername,
|
Username: Cmd.MqttUsername,
|
||||||
Password: Cmd.MqttPassword,
|
Password: Cmd.MqttPassword,
|
||||||
@ -83,24 +109,23 @@ func (ca *CommandArgs) MqttArgs(cmd *cobra.Command, args []string) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.SetDeviceConfig("GoSunGrow", strconv.FormatInt(id, 10), "GoSungrow", model, "Sungrow", "Roof")
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
Cmd.Error = Cmd.Mqtt.Connect()
|
Cmd.Error = Cmd.Mqtt.Connect()
|
||||||
if Cmd.Error != nil {
|
if Cmd.Error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPrintDate("Connecting to SunGrow...\n")
|
// if Cmd.Mqtt.PsId == 0 {
|
||||||
Cmd.Error = Cmd.SunGrowArgs(cmd, args)
|
// Cmd.Mqtt.PsId, Cmd.Error = Cmd.SunGrow.GetPsId()
|
||||||
if Cmd.Error != nil {
|
// if Cmd.Error != nil {
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
|
// LogPrintDate("Found SunGrow device %d\n", Cmd.Mqtt.PsId)
|
||||||
if Cmd.Mqtt.PsId == 0 {
|
// }
|
||||||
Cmd.Mqtt.PsId, Cmd.Error = Cmd.SunGrow.GetPsId()
|
|
||||||
if Cmd.Error != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
LogPrintDate("Found SunGrow device %d\n", Cmd.Mqtt.PsId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cmd.Error
|
return Cmd.Error
|
||||||
@ -231,21 +256,64 @@ func MqttCron() error {
|
|||||||
time.Sleep(time.Second * 40) // Takes up to 40 seconds for data to come in.
|
time.Sleep(time.Second * 40) // Takes up to 40 seconds for data to come in.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newDay := false
|
||||||
|
if Cmd.Mqtt.IsNewDay() {
|
||||||
|
newDay = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Update1(newDay)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Update2(newDay)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Mqtt.LastRefresh = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
LogPrintDate("Error: %s\n", Cmd.Error)
|
||||||
|
}
|
||||||
|
return Cmd.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func Update1(newDay bool) error {
|
||||||
|
for range Only.Once {
|
||||||
// Also getPowerStatistics, getHouseholdStoragePsReport, getPsList, getUpTimePoint,
|
// Also getPowerStatistics, getHouseholdStoragePsReport, getPsList, getUpTimePoint,
|
||||||
ep := Cmd.SunGrow.QueryDevice(Cmd.Mqtt.PsId)
|
ep := Cmd.SunGrow.QueryDevice(Cmd.Mqtt.PsId)
|
||||||
if ep.IsError() {
|
if ep.IsError() {
|
||||||
Cmd.Error = ep.GetError()
|
Cmd.Error = ep.GetError()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
data := ep.GetData()
|
data := ep.GetData()
|
||||||
|
|
||||||
if Cmd.Mqtt.IsNewDay() {
|
if newDay {
|
||||||
LogPrintDate("New day: Configuring %d entries in HASSIO.\n", len(data.Entries))
|
LogPrintDate("New day: Configuring %d entries in HASSIO.\n", len(data.Entries))
|
||||||
for _, r := range data.Entries {
|
for _, r := range data.Entries {
|
||||||
fmt.Printf(".")
|
fmt.Printf("C")
|
||||||
// Cmd.Error = Cmd.Mqtt.SensorPublishConfig(r.PointId, r.PointName, r.Unit, i)
|
re := mmHa.EntityConfig {
|
||||||
Cmd.Error = Cmd.Mqtt.SensorPublishConfig(r)
|
Type: r.ValueType.Type,
|
||||||
|
Name: r.ValueType.Id, // PointName,
|
||||||
|
SubName: "",
|
||||||
|
ParentId: r.ValueType.PsKey,
|
||||||
|
ParentName: "",
|
||||||
|
UniqueId: r.PointId,
|
||||||
|
FullName: r.ValueType.Description,
|
||||||
|
Units: r.Unit,
|
||||||
|
ValueName: r.PointId,
|
||||||
|
Class: "",
|
||||||
|
Value: r.Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.BinarySensorPublishConfig(re)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.SensorPublishConfig(re)
|
||||||
if Cmd.Error != nil {
|
if Cmd.Error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -255,20 +323,111 @@ func MqttCron() error {
|
|||||||
|
|
||||||
LogPrintDate("Updating %d entries to HASSIO.\n", len(data.Entries))
|
LogPrintDate("Updating %d entries to HASSIO.\n", len(data.Entries))
|
||||||
for _, r := range data.Entries {
|
for _, r := range data.Entries {
|
||||||
fmt.Printf(".")
|
fmt.Printf("U")
|
||||||
// Cmd.Error = Cmd.Mqtt.SensorPublishState(r.PointId, r.Value)
|
re := mmHa.EntityConfig {
|
||||||
Cmd.Error = Cmd.Mqtt.SensorPublishValue(r)
|
Type: r.ValueType.Type,
|
||||||
|
Name: r.ValueType.Id, // PointName,
|
||||||
|
SubName: "",
|
||||||
|
ParentId: r.ValueType.PsKey,
|
||||||
|
ParentName: "",
|
||||||
|
UniqueId: r.PointId,
|
||||||
|
FullName: r.ValueType.Description,
|
||||||
|
Units: r.Unit,
|
||||||
|
ValueName: r.PointId,
|
||||||
|
Class: "",
|
||||||
|
Value: r.Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.BinarySensorPublishValue(re)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.SensorPublishValue(re)
|
||||||
if Cmd.Error != nil {
|
if Cmd.Error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
Cmd.Mqtt.LastRefresh = time.Now()
|
if Cmd.Error != nil {
|
||||||
|
LogPrintDate("Error: %s\n", Cmd.Error)
|
||||||
|
}
|
||||||
|
return Cmd.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func Update2(newDay bool) error {
|
||||||
|
for range Only.Once {
|
||||||
|
// Also getPowerStatistics, getHouseholdStoragePsReport, getPsList, getUpTimePoint,
|
||||||
|
ep := Cmd.SunGrow.QueryPs(Cmd.Mqtt.PsId)
|
||||||
|
if ep.IsError() {
|
||||||
|
Cmd.Error = ep.GetError()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
data := ep.GetData()
|
||||||
|
|
||||||
|
if newDay {
|
||||||
|
LogPrintDate("New day: Configuring %d entries in HASSIO.\n", len(data.Entries))
|
||||||
|
for _, r := range data.Entries {
|
||||||
|
fmt.Printf("C")
|
||||||
|
|
||||||
|
re := mmHa.EntityConfig {
|
||||||
|
Type: r.ValueType.Type,
|
||||||
|
Name: r.ValueType.Id, // PointName,
|
||||||
|
SubName: "",
|
||||||
|
ParentId: r.ValueType.PsKey,
|
||||||
|
ParentName: "",
|
||||||
|
UniqueId: r.PointId,
|
||||||
|
FullName: r.ValueType.Description,
|
||||||
|
Units: r.Unit,
|
||||||
|
ValueName: r.PointId,
|
||||||
|
Class: "",
|
||||||
|
Value: r.Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.BinarySensorPublishConfig(re)
|
||||||
if Cmd.Error != nil {
|
if Cmd.Error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.SensorPublishConfig(re)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrintDate("Updating %d entries to HASSIO.\n", len(data.Entries))
|
||||||
|
for _, r := range data.Entries {
|
||||||
|
fmt.Printf("U")
|
||||||
|
|
||||||
|
re := mmHa.EntityConfig {
|
||||||
|
Type: r.ValueType.Type,
|
||||||
|
Name: r.ValueType.Id, // PointName,
|
||||||
|
SubName: "",
|
||||||
|
ParentId: r.ValueType.PsKey,
|
||||||
|
ParentName: "",
|
||||||
|
UniqueId: r.PointId,
|
||||||
|
FullName: r.ValueType.Description,
|
||||||
|
Units: r.Unit,
|
||||||
|
ValueName: r.PointId,
|
||||||
|
Class: "",
|
||||||
|
Value: r.Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.BinarySensorPublishValue(re)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd.Error = Cmd.Mqtt.SensorPublishValue(re)
|
||||||
|
if Cmd.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
if Cmd.Error != nil {
|
if Cmd.Error != nil {
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"GoSungrow/iSolarCloud/AppService/login"
|
"GoSungrow/iSolarCloud/AppService/login"
|
||||||
"GoSungrow/lsgo"
|
"GoSungrow/lsgo"
|
||||||
"GoSungrow/mmGit"
|
"GoSungrow/mmGit"
|
||||||
"GoSungrow/mmMqtt"
|
"GoSungrow/mmHa"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -21,7 +21,7 @@ var DefaultAreas = []string{"all"}
|
|||||||
type CommandArgs struct {
|
type CommandArgs struct {
|
||||||
SunGrow *iSolarCloud.SunGrow
|
SunGrow *iSolarCloud.SunGrow
|
||||||
Git *mmGit.Git
|
Git *mmGit.Git
|
||||||
Mqtt *mmMqtt.Mqtt
|
Mqtt *mmHa.Mqtt
|
||||||
|
|
||||||
ConfigDir string
|
ConfigDir string
|
||||||
CacheDir string
|
CacheDir string
|
||||||
|
@ -192,7 +192,7 @@ func (e *EndPoint) GetDataTable() output.Table {
|
|||||||
keys := api.GetStructKeys(e.Response.ResultData)
|
keys := api.GetStructKeys(e.Response.ResultData)
|
||||||
for _, n := range keys.Sort() {
|
for _, n := range keys.Sort() {
|
||||||
p := api.GetPoint(e.Response.ResultData.PsPsKey, n)
|
p := api.GetPoint(e.Response.ResultData.PsPsKey, n)
|
||||||
if p != nil {
|
if p.Valid {
|
||||||
_ = table.AddRow(
|
_ = table.AddRow(
|
||||||
now,
|
now,
|
||||||
api.NameDevicePoint(e.Response.ResultData.PsPsKey, n),
|
api.NameDevicePoint(e.Response.ResultData.PsPsKey, n),
|
||||||
@ -222,7 +222,7 @@ func (e *EndPoint) GetDataTable() output.Table {
|
|||||||
keys = api.GetStructKeys(sid)
|
keys = api.GetStructKeys(sid)
|
||||||
for _, n := range keys.Sort() {
|
for _, n := range keys.Sort() {
|
||||||
p := api.GetPoint(sid.PsKey, n)
|
p := api.GetPoint(sid.PsKey, n)
|
||||||
if p != nil {
|
if p.Valid {
|
||||||
_ = table.AddRow(
|
_ = table.AddRow(
|
||||||
now,
|
now,
|
||||||
api.NameDevicePoint(sid.PsKey, n),
|
api.NameDevicePoint(sid.PsKey, n),
|
||||||
@ -304,6 +304,45 @@ func (e *EndPoint) GetPsKeys() []string {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetPsName() string {
|
||||||
|
return e.Response.ResultData.PsName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetPsState() string {
|
||||||
|
return e.Response.ResultData.PsState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetPsKey() string {
|
||||||
|
return e.Response.ResultData.PsPsKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetDeviceModelCode() string {
|
||||||
|
ret := e.Response.ResultData.PsPsKey
|
||||||
|
for _, l := range e.Response.ResultData.StorageInverterData {
|
||||||
|
ret = l.DeviceModelCode
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetDeviceName() string {
|
||||||
|
ret := e.Response.ResultData.PsPsKey
|
||||||
|
for _, l := range e.Response.ResultData.StorageInverterData {
|
||||||
|
ret = l.DeviceName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetDeviceSerial() string {
|
||||||
|
ret := e.Response.ResultData.PsPsKey
|
||||||
|
for _, l := range e.Response.ResultData.StorageInverterData {
|
||||||
|
ret = l.InverterSn
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// ChargingDischargingPowerMap
|
// ChargingDischargingPowerMap
|
||||||
// Co2ReduceTotal
|
// Co2ReduceTotal
|
||||||
// CoalReduceTotal
|
// CoalReduceTotal
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"GoSungrow/iSolarCloud/api/apiReflect"
|
"GoSungrow/iSolarCloud/api/apiReflect"
|
||||||
"GoSungrow/iSolarCloud/api/output"
|
"GoSungrow/iSolarCloud/api/output"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -200,44 +201,239 @@ func (e *ResultData) GetPsId() int64 {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EndPoint) GetPsId() int64 {
|
func (e *ResultData) GetPsName() string {
|
||||||
return e.Response.ResultData.GetPsId()
|
var ret string
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ResultData) GetData() [][]string {
|
|
||||||
var ret [][]string
|
|
||||||
for range Only.Once {
|
for range Only.Once {
|
||||||
i := len(e.PageList)
|
i := len(e.PageList)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
now := time.Now().Round(5 * time.Minute).Format(api.DtLayoutZeroSeconds)
|
|
||||||
for _, p := range e.PageList {
|
for _, p := range e.PageList {
|
||||||
ret = append(ret, []string{now, "Co2 Reduce", p.Co2Reduce.Value, p.Co2Reduce.Unit})
|
if p.PsID != 0 {
|
||||||
ret = append(ret, []string{now, "Co2 Reduce Total", p.Co2ReduceTotal.Value, p.Co2ReduceTotal.Unit})
|
ret = p.PsName
|
||||||
ret = append(ret, []string{now, "Curr Power", p.CurrPower.Value, p.CurrPower.Unit})
|
break
|
||||||
ret = append(ret, []string{now, "Daily Irradiation", p.DailyIrradiation.Value, p.DailyIrradiation.Unit})
|
}
|
||||||
ret = append(ret, []string{now, "Equivalent Hour", p.EquivalentHour.Value, p.EquivalentHour.Unit})
|
|
||||||
ret = append(ret, []string{now, "Es Discharge Energy", p.EsDisenergy.Value, p.EsDisenergy.Unit})
|
|
||||||
ret = append(ret, []string{now, "Es Energy", p.EsEnergy.Value, p.EsEnergy.Unit})
|
|
||||||
ret = append(ret, []string{now, "Es Power", p.EsPower.Value, p.EsPower.Unit})
|
|
||||||
ret = append(ret, []string{now, "Es Total Discharge Energy", p.EsTotalDisenergy.Value, p.EsTotalDisenergy.Unit})
|
|
||||||
ret = append(ret, []string{now, "Es Total Energy", p.EsTotalEnergy.Value, p.EsTotalEnergy.Unit})
|
|
||||||
ret = append(ret, []string{now, "Installed Power Map", p.InstalledPowerMap.Value, p.InstalledPowerMap.Unit})
|
|
||||||
ret = append(ret, []string{now, "Pv Energy", p.PvEnergy.Value, p.PvEnergy.Unit})
|
|
||||||
ret = append(ret, []string{now, "Pv Power", p.PvPower.Value, p.PvPower.Unit})
|
|
||||||
ret = append(ret, []string{now, "Radiation", p.Radiation.Value, p.Radiation.Unit})
|
|
||||||
ret = append(ret, []string{now, "Today Energy", p.TodayEnergy.Value, p.TodayEnergy.Unit})
|
|
||||||
ret = append(ret, []string{now, "Today Income", p.TodayIncome.Value, p.TodayIncome.Unit})
|
|
||||||
ret = append(ret, []string{now, "Total Capacity", p.TotalCapcity.Value, p.TotalCapcity.Unit})
|
|
||||||
ret = append(ret, []string{now, "Total Energy", p.TotalEnergy.Value, p.TotalEnergy.Unit})
|
|
||||||
ret = append(ret, []string{now, "Total Income", p.TotalIncome.Value, p.TotalIncome.Unit})
|
|
||||||
ret = append(ret, []string{now, "Use Energy", p.UseEnergy.Value, p.UseEnergy.Unit})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *ResultData) GetPsSerial() string {
|
||||||
|
var ret string
|
||||||
|
for range Only.Once {
|
||||||
|
i := len(e.PageList)
|
||||||
|
if i == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, p := range e.PageList {
|
||||||
|
if p.PsID != 0 {
|
||||||
|
ret = p.PsShortName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetPsId() int64 {
|
||||||
|
return e.Response.ResultData.GetPsId()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EndPoint) GetData() api.Data {
|
||||||
|
return e.Response.ResultData.GetData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ResultData) GetData() api.Data {
|
||||||
|
var ret api.Data
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
i := len(e.PageList)
|
||||||
|
if i == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
now := api.NewDateTime(time.Now().Round(5 * time.Minute).Format(api.DtLayoutZeroSeconds))
|
||||||
|
|
||||||
|
for _, p := range e.PageList {
|
||||||
|
psId := strconv.FormatInt(p.PsID, 10)
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83077", "Pv Energy", p.PvEnergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83089", "Es Discharge Energy", p.EsDisenergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83095", "Es Total Discharge Energy", p.EsTotalDisenergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83118", "Use Energy", p.UseEnergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83120", "Es Energy", p.EsEnergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83127", "Es Total Energy", p.EsTotalEnergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83076", "Pv Power", p.PvPower, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "p83081", "Es Power", p.EsPower, len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "co2_reduce", "Co2 Reduce", p.Co2Reduce, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "co2_reduce_total", "Co2 Reduce Total", p.Co2ReduceTotal, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "curr_power", "Curr Power", p.CurrPower, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "daily_irradiation", "Daily Irradiation", p.DailyIrradiation, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "equivalent_hour", "Equivalent Hour", p.EquivalentHour, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "installed_power_map", "Installed Power Map", p.InstalledPowerMap, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "radiation", "Radiation", p.Radiation, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "today_energy", "Today Energy", p.TodayEnergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "today_income", "Today Income", p.TodayIncome, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "total_capacity", "Total Capacity", p.TotalCapcity, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "total_energy", "Total Energy", p.TotalEnergy, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, add(now, psId, "total_income", "Total Income", p.TotalIncome, len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addValue(now, psId, "build_date", "Build Date", p.BuildDate, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addIntValue(now, psId, "build_status", "Build Status", p.BuildStatus, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(now, psId, "latitude", "Latitude", p.Latitude, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(now, psId, "longitude", "Longitude", p.Longitude, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addValue(now, psId, "location", "Location", p.Location, len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addIntValue(now, psId, "installer_ps_fault_status", "Installer PS Fault Status", p.InstallerPsFaultStatus, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addIntValue(now, psId, "owner_ps_fault_status", "Owner PS Fault Status", p.OwnerPsFaultStatus, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addIntValue(now, psId, "ps_fault_status", "PS Fault Status", p.PsFaultStatus, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addValue(now, psId, "ps_health_status", "PS Health Status", p.PsHealthStatus, len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addValue(now, psId, "ps_holder", "PS Holder", p.PsHolder, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addIntValue(now, psId, "ps_id", "PS Id", p.PsID, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addValue(now, psId, "ps_name", "PS Name", p.PsName, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addValue(now, psId, "ps_short_name", "PS Short Name", p.PsShortName, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addIntValue(now, psId, "ps_status", "PS Status", p.PsStatus, len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addIntValue(now, psId, "ps_type", "PS Type", p.PsType, len(ret.Entries)))
|
||||||
|
|
||||||
|
// ret = append(ret, []string{now, "Pv Energy", p.PvEnergy.Value, p.PvEnergy.Unit}) // p83077
|
||||||
|
// ret = append(ret, []string{now, "Es Discharge Energy", p.EsDisenergy.Value, p.EsDisenergy.Unit}) // p83089
|
||||||
|
// ret = append(ret, []string{now, "Es Total Discharge Energy", p.EsTotalDisenergy.Value, p.EsTotalDisenergy.Unit}) // p83095
|
||||||
|
// ret = append(ret, []string{now, "Use Energy", p.UseEnergy.Value, p.UseEnergy.Unit}) // p83118
|
||||||
|
// ret = append(ret, []string{now, "Es Energy", p.EsEnergy.Value, p.EsEnergy.Unit}) // p83120
|
||||||
|
// ret = append(ret, []string{now, "Es Total Energy", p.EsTotalEnergy.Value, p.EsTotalEnergy.Unit}) // p83127
|
||||||
|
// ret = append(ret, []string{now, "Pv Power", p.PvPower.Value, p.PvPower.Unit}) // p83076
|
||||||
|
// ret = append(ret, []string{now, "Es Power", p.EsPower.Value, p.EsPower.Unit}) // p83081
|
||||||
|
//
|
||||||
|
// ret = append(ret, []string{now, "Co2 Reduce", p.Co2Reduce.Value, p.Co2Reduce.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Co2 Reduce Total", p.Co2ReduceTotal.Value, p.Co2ReduceTotal.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Curr Power", p.CurrPower.Value, p.CurrPower.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Daily Irradiation", p.DailyIrradiation.Value, p.DailyIrradiation.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Equivalent Hour", p.EquivalentHour.Value, p.EquivalentHour.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Installed Power Map", p.InstalledPowerMap.Value, p.InstalledPowerMap.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Radiation", p.Radiation.Value, p.Radiation.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Today Energy", p.TodayEnergy.Value, p.TodayEnergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Today Income", p.TodayIncome.Value, p.TodayIncome.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Total Capacity", p.TotalCapcity.Value, p.TotalCapcity.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Total Energy", p.TotalEnergy.Value, p.TotalEnergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Total Income", p.TotalIncome.Value, p.TotalIncome.Unit})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func addState(now api.DateTime, point string, name string, state bool, index int) api.DataEntry {
|
||||||
|
return add(now, "virtual", point, name, api.UnitValue{ Value: fmt.Sprintf("%v", state) }, index)
|
||||||
|
|
||||||
|
// return api.DataEntry {
|
||||||
|
// Date: now,
|
||||||
|
// PointId: api.NameDevicePoint("virtual", point),
|
||||||
|
// PointGroupName: "Virtual",
|
||||||
|
// PointName: name,
|
||||||
|
// Value: fmt.Sprintf("%v", state),
|
||||||
|
// Unit: "binary",
|
||||||
|
// ValueType: &api.Point{
|
||||||
|
// PsKey: "virtual",
|
||||||
|
// Id: point,
|
||||||
|
// Description: name,
|
||||||
|
// Unit: "binary",
|
||||||
|
// Type: "PointTypeInstant",
|
||||||
|
// },
|
||||||
|
// Index: index,
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func addValue(now api.DateTime, psId string, point string, name string, value string, index int) api.DataEntry {
|
||||||
|
return add(now, psId, point, name, api.UnitValue{ Value: value }, index)
|
||||||
|
|
||||||
|
// vt := api.GetPoint(psId, point)
|
||||||
|
// if !vt.Valid {
|
||||||
|
// vt = &api.Point{
|
||||||
|
// PsKey: psId,
|
||||||
|
// Id: point,
|
||||||
|
// Description: name,
|
||||||
|
// Unit: "",
|
||||||
|
// Type: "PointTypeInstant",
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return api.DataEntry {
|
||||||
|
// Date: now,
|
||||||
|
// PointId: api.NameDevicePoint(psId, point),
|
||||||
|
// PointGroupName: "Summary",
|
||||||
|
// PointName: name,
|
||||||
|
// Value: value,
|
||||||
|
// Unit: "",
|
||||||
|
// ValueType: vt,
|
||||||
|
// Index: index,
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func addIntValue(now api.DateTime, psId string, point string, name string, value int64, index int) api.DataEntry {
|
||||||
|
return add(now, psId, point, name, api.UnitValue{ Value: strconv.FormatInt(value, 10) }, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFloatValue(now api.DateTime, psId string, point string, name string, value float64, index int) api.DataEntry {
|
||||||
|
return add(now, psId, point, name, api.UnitValue{ Value: api.Float64ToString(value) }, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(now api.DateTime, psId string, point string, name string, value api.UnitValue, index int) api.DataEntry {
|
||||||
|
vt := api.GetPoint(psId, point)
|
||||||
|
if !vt.Valid {
|
||||||
|
vt = &api.Point{
|
||||||
|
PsKey: psId,
|
||||||
|
Id: point,
|
||||||
|
Description: name,
|
||||||
|
Unit: value.Unit,
|
||||||
|
Type: "PointTypeInstant",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return api.DataEntry {
|
||||||
|
Date: now,
|
||||||
|
PointId: api.NameDevicePoint(psId, point),
|
||||||
|
PointGroupName: "Virtual",
|
||||||
|
PointName: name,
|
||||||
|
Value: value.Value,
|
||||||
|
Unit: value.Unit,
|
||||||
|
ValueType: vt,
|
||||||
|
Index: index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (e *ResultData) GetData() [][]string {
|
||||||
|
// var ret [][]string
|
||||||
|
// for range Only.Once {
|
||||||
|
// i := len(e.PageList)
|
||||||
|
// if i == 0 {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// now := time.Now().Round(5 * time.Minute).Format(api.DtLayoutZeroSeconds)
|
||||||
|
// for _, p := range e.PageList {
|
||||||
|
// ret = append(ret, []string{now, "Co2 Reduce", p.Co2Reduce.Value, p.Co2Reduce.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Co2 Reduce Total", p.Co2ReduceTotal.Value, p.Co2ReduceTotal.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Curr Power", p.CurrPower.Value, p.CurrPower.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Daily Irradiation", p.DailyIrradiation.Value, p.DailyIrradiation.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Equivalent Hour", p.EquivalentHour.Value, p.EquivalentHour.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Es Discharge Energy", p.EsDisenergy.Value, p.EsDisenergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Es Energy", p.EsEnergy.Value, p.EsEnergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Es Power", p.EsPower.Value, p.EsPower.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Es Total Discharge Energy", p.EsTotalDisenergy.Value, p.EsTotalDisenergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Es Total Energy", p.EsTotalEnergy.Value, p.EsTotalEnergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Installed Power Map", p.InstalledPowerMap.Value, p.InstalledPowerMap.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Pv Energy", p.PvEnergy.Value, p.PvEnergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Pv Power", p.PvPower.Value, p.PvPower.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Radiation", p.Radiation.Value, p.Radiation.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Today Energy", p.TodayEnergy.Value, p.TodayEnergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Today Income", p.TodayIncome.Value, p.TodayIncome.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Total Capacity", p.TotalCapcity.Value, p.TotalCapcity.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Total Energy", p.TotalEnergy.Value, p.TotalEnergy.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Total Income", p.TotalIncome.Value, p.TotalIncome.Unit})
|
||||||
|
// ret = append(ret, []string{now, "Use Energy", p.UseEnergy.Value, p.UseEnergy.Unit})
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return ret
|
||||||
|
// }
|
||||||
|
|
||||||
func (e *EndPoint) GetDataTable() output.Table {
|
func (e *EndPoint) GetDataTable() output.Table {
|
||||||
var table output.Table
|
var table output.Table
|
||||||
for range Only.Once {
|
for range Only.Once {
|
||||||
|
@ -298,7 +298,9 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
|
|
||||||
var TotalDcPower float64
|
var TotalDcPower float64
|
||||||
|
|
||||||
index := 0
|
var TotalLoadActivePower float64
|
||||||
|
|
||||||
|
// index := 0
|
||||||
for _, d := range e.Response.ResultData.PageList {
|
for _, d := range e.Response.ResultData.PageList {
|
||||||
for _, p := range d.PointData {
|
for _, p := range d.PointData {
|
||||||
if p.Unit == "W" {
|
if p.Unit == "W" {
|
||||||
@ -323,6 +325,16 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vt := api.GetPointInt(d.PsKey, p.PointID)
|
||||||
|
if !vt.Valid {
|
||||||
|
vt = &api.Point{
|
||||||
|
PsKey: d.PsKey,
|
||||||
|
Id: "p" + strings.TrimPrefix(strconv.FormatInt(p.PointID, 10), "p"),
|
||||||
|
Description: p.PointName,
|
||||||
|
Unit: p.Unit,
|
||||||
|
Type: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
ret.Entries = append(ret.Entries, api.DataEntry {
|
||||||
Date: api.NewDateTime(p.TimeStamp),
|
Date: api.NewDateTime(p.TimeStamp),
|
||||||
PointId: api.NameDevicePointInt(d.PsKey, p.PointID),
|
PointId: api.NameDevicePointInt(d.PsKey, p.PointID),
|
||||||
@ -330,12 +342,10 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
PointName: p.PointName,
|
PointName: p.PointName,
|
||||||
Value: p.Value,
|
Value: p.Value,
|
||||||
Unit: p.Unit,
|
Unit: p.Unit,
|
||||||
ValueType: api.GetPointInt(d.PsKey, p.PointID),
|
ValueType: vt,
|
||||||
Index: index,
|
Index: len(ret.Entries),
|
||||||
})
|
})
|
||||||
|
|
||||||
index++
|
|
||||||
|
|
||||||
// Handle virtual results.
|
// Handle virtual results.
|
||||||
switch strings.ReplaceAll(p.PointName, " ", "") {
|
switch strings.ReplaceAll(p.PointName, " ", "") {
|
||||||
case "BatteryChargingPower":
|
case "BatteryChargingPower":
|
||||||
@ -346,6 +356,11 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
TotalExportActivePower, _ = strconv.ParseFloat(p.Value, 64)
|
TotalExportActivePower, _ = strconv.ParseFloat(p.Value, 64)
|
||||||
case "PurchasedPower":
|
case "PurchasedPower":
|
||||||
PurchasedPower, _ = strconv.ParseFloat(p.Value, 64)
|
PurchasedPower, _ = strconv.ParseFloat(p.Value, 64)
|
||||||
|
case "TotalDCPower":
|
||||||
|
TotalDcPower, _ = strconv.ParseFloat(p.Value, 64)
|
||||||
|
case "TotalLoadActivePower":
|
||||||
|
TotalLoadActivePower, _ = strconv.ParseFloat(p.Value, 64)
|
||||||
|
|
||||||
case "DailyBatteryChargingEnergyFromPv":
|
case "DailyBatteryChargingEnergyFromPv":
|
||||||
DailyBatteryChargingEnergyFromPv, _ = strconv.ParseFloat(p.Value, 64)
|
DailyBatteryChargingEnergyFromPv, _ = strconv.ParseFloat(p.Value, 64)
|
||||||
case "DailyBatteryDischargingEnergy":
|
case "DailyBatteryDischargingEnergy":
|
||||||
@ -354,8 +369,6 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
DailyFeedInEnergyPv, _ = strconv.ParseFloat(p.Value, 64)
|
DailyFeedInEnergyPv, _ = strconv.ParseFloat(p.Value, 64)
|
||||||
case "DailyPurchasedEnergy":
|
case "DailyPurchasedEnergy":
|
||||||
DailyPurchasedEnergy, _ = strconv.ParseFloat(p.Value, 64)
|
DailyPurchasedEnergy, _ = strconv.ParseFloat(p.Value, 64)
|
||||||
case "TotalDCPower":
|
|
||||||
TotalDcPower, _ = strconv.ParseFloat(p.Value, 64)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,66 +379,165 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
|
|
||||||
// Add virtual entries.
|
// Add virtual entries.
|
||||||
ts := ret.Entries[0].Date
|
ts := ret.Entries[0].Date
|
||||||
var value string
|
var value float64
|
||||||
|
|
||||||
if BatteryChargingPower > 0 {
|
/*
|
||||||
value = api.Float64ToString(0 - BatteryChargingPower)
|
PVPower - TotalDcPower
|
||||||
} else {
|
PVPowerToBattery - BatteryChargingPower
|
||||||
value = api.Float64ToString(BatteryDischargingPower)
|
PVPowerToLoad - TotalDcPower - BatteryChargingPower - TotalExportActivePower
|
||||||
}
|
PVPowerToGrid - TotalExportActivePower
|
||||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
|
||||||
Date: ts,
|
|
||||||
PointId: "virtual.battery_power",
|
|
||||||
PointGroupName: "Virtual",
|
|
||||||
PointName: "Battery Power",
|
|
||||||
Value: value,
|
|
||||||
Unit: "kW",
|
|
||||||
ValueType: &api.Point {
|
|
||||||
PsKey: "virtual",
|
|
||||||
Id: "battery_power",
|
|
||||||
Description: "Battery Power",
|
|
||||||
Unit: "kW",
|
|
||||||
Type: "PointTypeInstant",
|
|
||||||
},
|
|
||||||
Index: index,
|
|
||||||
})
|
|
||||||
index++
|
|
||||||
|
|
||||||
if TotalExportActivePower > 0 {
|
LoadPower - TotalLoadActivePower
|
||||||
value = api.Float64ToString(0 - TotalExportActivePower)
|
BatteryToLoad - BatteryDischargingPower
|
||||||
} else {
|
BatteryToGrid - ?
|
||||||
value = api.Float64ToString(PurchasedPower)
|
|
||||||
}
|
GridPower - TotalDcPower
|
||||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
GridToLoad - PurchasedPower
|
||||||
Date: ts,
|
GridToBattery - ?
|
||||||
PointId: "virtual.grid_power",
|
*/
|
||||||
PointGroupName: "Virtual",
|
|
||||||
PointName: "Grid Power",
|
|
||||||
Value: value,
|
|
||||||
Unit: "kW",
|
|
||||||
ValueType: &api.Point {
|
|
||||||
PsKey: "virtual",
|
|
||||||
Id: "grid_power",
|
|
||||||
Description: "Grid Power",
|
|
||||||
Unit: "kW",
|
|
||||||
Type: "PointTypeInstant",
|
|
||||||
},
|
|
||||||
Index: index,
|
|
||||||
})
|
|
||||||
index++
|
|
||||||
|
|
||||||
|
|
||||||
|
PVPower := TotalDcPower
|
||||||
|
PVPowerToBattery := BatteryChargingPower
|
||||||
|
PVPowerToLoad := TotalDcPower - BatteryChargingPower - TotalExportActivePower
|
||||||
|
PVPowerToGrid := TotalExportActivePower
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "pv_power_active", "PV Power Active", isActive(PVPower), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "pv_power", "PV Power", PVPower, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "pv_power_to_battery_active", "PV Power To Battery Active", isActive(PVPowerToBattery), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "pv_power_to_battery", "PV Power To Battery", PVPowerToBattery, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "pv_power_to_load_active", "PV Power To Load Active", isActive(PVPowerToLoad), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "pv_power_to_load", "PV Power To Load", PVPowerToLoad, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "pv_power_to_grid_active", "PV Power To Grid Active", isActive(PVPowerToGrid), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "pv_power_to_grid", "PV Power To Grid", PVPowerToGrid, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
|
||||||
|
BatteryPower := lowerUpper(BatteryChargingPower, BatteryDischargingPower)
|
||||||
|
BatteryToLoad := BatteryDischargingPower
|
||||||
|
BatteryToGrid := 0.0
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "battery_power_active", "Battery Power Active", isActive(BatteryPower), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "battery_power", "Battery Power", BatteryPower, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "battery_power_to_load_active", "Battery Power To Load Active", isActive(BatteryToLoad), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "battery_power_to_load", "Battery Power To Load", BatteryToLoad, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "battery_power_to_grid_active", "Battery Power To Grid Active", isActive(BatteryToGrid), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "battery_power_to_grid", "Battery Power To Grid", BatteryToGrid, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
|
||||||
|
GridPower := lowerUpper(TotalExportActivePower, PurchasedPower)
|
||||||
|
GridToLoad := PurchasedPower
|
||||||
|
GridToBattery := 0.0
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "grid_power_active", "Grid Power Active", isActive(GridPower), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "grid_power", "Grid Power", GridPower, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "grid_power_to_load_active", "Grid Power To Load Active", isActive(GridToLoad), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "grid_power_to_load", "Grid Power To Load", GridToLoad, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "grid_power_to_battery_active", "Grid Power To Battery Active", isActive(GridToBattery), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "grid_power_to_battery", "Grid Power To Battery", GridToBattery, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
|
||||||
|
LoadPower := TotalLoadActivePower
|
||||||
|
ret.Entries = append(ret.Entries, addState(ts, "load_power_active", "Load Power Active", isActive(LoadPower), len(ret.Entries)))
|
||||||
|
ret.Entries = append(ret.Entries, addFloatValue(ts, "load_power", "Load Power", LoadPower, "kW", len(ret.Entries)))
|
||||||
|
|
||||||
|
|
||||||
|
// {
|
||||||
|
// if isActive(BatteryChargingPower) {
|
||||||
|
// value = 0 - BatteryChargingPower
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "battery_power_active", "Battery Power Active", true, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "pv_flow_to_battery", "PV Flow To Battery", true, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "battery_flow_to_load", "Battery Flow To Load", false, len(ret.Entries)))
|
||||||
|
//
|
||||||
|
// } else if isActive(BatteryDischargingPower) {
|
||||||
|
// value = BatteryDischargingPower
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "battery_power_active", "Battery Power Active", true, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "pv_flow_to_battery", "PV Flow To Battery", false, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "battery_flow_to_load", "Battery Flow To Load", true, len(ret.Entries)))
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// value = 0
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "battery_power_active", "Battery Power Active", false, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "pv_flow_to_battery", "PV Flow To Battery", false, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "battery_flow_to_load", "Battery Flow To Load", false, len(ret.Entries)))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addFloatValue(ts, "battery_power", "Battery Power", value, len(ret.Entries)))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// if isActive(TotalExportActivePower) {
|
||||||
|
// value = 0 - TotalExportActivePower
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "grid_power_active", "Grid Power Active", true, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "pv_flow_to_grid", "PV Flow To Grid", true, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "grid_flow_to_load", "Grid Flow To Load", false, len(ret.Entries)))
|
||||||
|
//
|
||||||
|
// } else if isActive(PurchasedPower) {
|
||||||
|
// value = PurchasedPower
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "grid_power_active", "Grid Power Active", true, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "pv_flow_to_grid", "PV Flow To Grid", false, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "grid_flow_to_load", "Grid Flow To Load", true, len(ret.Entries)))
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// value = 0
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "grid_power_active", "Grid Power Active", false, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "pv_flow_to_grid", "PV Flow To Grid", false, len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "grid_flow_to_load", "Grid Flow To Load", false, len(ret.Entries)))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, addFloatValue(ts, "grid_power", "Grid Power", value, len(ret.Entries)))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "pv_power_active", "PV Power Active", isActive(TotalDcPower), len(ret.Entries)))
|
||||||
|
// ret.Entries = append(ret.Entries, addFloatValue(ts, "pv_power", "PV Power", TotalDcPower, len(ret.Entries)))
|
||||||
|
//
|
||||||
|
// value = TotalDcPower - BatteryChargingPower - TotalExportActivePower
|
||||||
|
// ret.Entries = append(ret.Entries, addFloatValue(ts, "pv_power_to_load", "PV Power To Load", value, len(ret.Entries)))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// ret.Entries = append(ret.Entries, addState(ts, "load_power_active", "Load Power Active", isActive(TotalLoadActivePower), len(ret.Entries)))
|
||||||
|
//
|
||||||
|
// ret.Entries = append(ret.Entries, api.DataEntry{
|
||||||
|
// Date: ts,
|
||||||
|
// PointId: "virtual.pv_power_to_grid",
|
||||||
|
// PointGroupName: "Virtual",
|
||||||
|
// PointName: "PV Power To Grid",
|
||||||
|
// Value: api.Float64ToString(TotalExportActivePower),
|
||||||
|
// Unit: "kW",
|
||||||
|
// ValueType: &api.Point{
|
||||||
|
// PsKey: "virtual",
|
||||||
|
// Id: "pv_power_to_grid",
|
||||||
|
// Description: "PV Power To Grid",
|
||||||
|
// Unit: "kW",
|
||||||
|
// Type: "PointTypeInstant",
|
||||||
|
// },
|
||||||
|
// Index: len(ret.Entries),
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
{
|
||||||
if DailyBatteryChargingEnergyFromPv > 0 {
|
if DailyBatteryChargingEnergyFromPv > 0 {
|
||||||
value = api.Float64ToString(0 - DailyBatteryChargingEnergyFromPv)
|
value = 0 - DailyBatteryChargingEnergyFromPv
|
||||||
} else {
|
} else {
|
||||||
value = api.Float64ToString(DailyBatteryDischargingEnergy)
|
value = DailyBatteryDischargingEnergy
|
||||||
}
|
}
|
||||||
ret.Entries = append(ret.Entries, api.DataEntry{
|
ret.Entries = append(ret.Entries, api.DataEntry{
|
||||||
Date: ts,
|
Date: ts,
|
||||||
PointId: "virtual.battery_energy",
|
PointId: "virtual.battery_energy",
|
||||||
PointGroupName: "Virtual",
|
PointGroupName: "Virtual",
|
||||||
PointName: "Battery Energy",
|
PointName: "Battery Energy",
|
||||||
Value: value,
|
Value: api.Float64ToString(value),
|
||||||
Unit: "kWh",
|
Unit: "kWh",
|
||||||
ValueType: &api.Point{
|
ValueType: &api.Point{
|
||||||
PsKey: "virtual",
|
PsKey: "virtual",
|
||||||
@ -434,21 +546,22 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
Unit: "kWh",
|
Unit: "kWh",
|
||||||
Type: "PointTypeInstant",
|
Type: "PointTypeInstant",
|
||||||
},
|
},
|
||||||
Index: index,
|
Index: len(ret.Entries),
|
||||||
})
|
})
|
||||||
index++
|
}
|
||||||
|
|
||||||
|
{
|
||||||
if DailyFeedInEnergyPv > 0 {
|
if DailyFeedInEnergyPv > 0 {
|
||||||
value = api.Float64ToString(0 - DailyFeedInEnergyPv)
|
value = 0 - DailyFeedInEnergyPv
|
||||||
} else {
|
} else {
|
||||||
value = api.Float64ToString(DailyPurchasedEnergy)
|
value = DailyPurchasedEnergy
|
||||||
}
|
}
|
||||||
ret.Entries = append(ret.Entries, api.DataEntry{
|
ret.Entries = append(ret.Entries, api.DataEntry{
|
||||||
Date: ts,
|
Date: ts,
|
||||||
PointId: "virtual.grid_energy",
|
PointId: "virtual.grid_energy",
|
||||||
PointGroupName: "Virtual",
|
PointGroupName: "Virtual",
|
||||||
PointName: "Grid Energy",
|
PointName: "Grid Energy",
|
||||||
Value: value,
|
Value: api.Float64ToString(value),
|
||||||
Unit: "kWh",
|
Unit: "kWh",
|
||||||
ValueType: &api.Point{
|
ValueType: &api.Point{
|
||||||
PsKey: "virtual",
|
PsKey: "virtual",
|
||||||
@ -457,31 +570,122 @@ func (e *EndPoint) GetData() api.Data {
|
|||||||
Unit: "kWh",
|
Unit: "kWh",
|
||||||
Type: "PointTypeInstant",
|
Type: "PointTypeInstant",
|
||||||
},
|
},
|
||||||
Index: index,
|
Index: len(ret.Entries),
|
||||||
})
|
})
|
||||||
index++
|
}
|
||||||
|
|
||||||
|
|
||||||
value = api.Float64ToString(TotalDcPower - BatteryChargingPower - TotalExportActivePower)
|
|
||||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
|
||||||
Date: ts,
|
|
||||||
PointId: "virtual.pv_to_load",
|
|
||||||
PointGroupName: "Virtual",
|
|
||||||
PointName: "PV To Load Power",
|
|
||||||
Value: value,
|
|
||||||
Unit: "kW",
|
|
||||||
ValueType: &api.Point {
|
|
||||||
PsKey: "virtual",
|
|
||||||
Id: "pv_to_load",
|
|
||||||
Description: "PV To Load Power",
|
|
||||||
Unit: "kW",
|
|
||||||
Type: "PointTypeInstant",
|
|
||||||
},
|
|
||||||
Index: index,
|
|
||||||
})
|
|
||||||
index++
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lowerUpper(lower float64, upper float64) float64 {
|
||||||
|
if lower > 0 {
|
||||||
|
return 0 - lower
|
||||||
|
}
|
||||||
|
return upper
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func addState(now api.DateTime, point string, name string, state bool, index int) api.DataEntry {
|
||||||
|
return add(now, "virtual", point, name, api.UnitValue{ Value: fmt.Sprintf("%v", state), Unit: "binary"}, index)
|
||||||
|
|
||||||
|
// return api.DataEntry {
|
||||||
|
// Date: now,
|
||||||
|
// PointId: api.NameDevicePoint("virtual", point),
|
||||||
|
// PointGroupName: "Virtual",
|
||||||
|
// PointName: name,
|
||||||
|
// Value: fmt.Sprintf("%v", state),
|
||||||
|
// Unit: "binary",
|
||||||
|
// ValueType: &api.Point{
|
||||||
|
// PsKey: "virtual",
|
||||||
|
// Id: point,
|
||||||
|
// Description: name,
|
||||||
|
// Unit: "binary",
|
||||||
|
// Type: "PointTypeInstant",
|
||||||
|
// },
|
||||||
|
// Index: index,
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func addValue(now api.DateTime, point string, name string, value string, unit string, index int) api.DataEntry {
|
||||||
|
return add(now, "virtual", point, name, api.UnitValue{ Value: value, Unit: unit}, index)
|
||||||
|
|
||||||
|
// vt := api.GetPoint(psId, point)
|
||||||
|
// if !vt.Valid {
|
||||||
|
// vt = &api.Point{
|
||||||
|
// PsKey: psId,
|
||||||
|
// Id: point,
|
||||||
|
// Description: name,
|
||||||
|
// Unit: "",
|
||||||
|
// Type: "PointTypeInstant",
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return api.DataEntry {
|
||||||
|
// Date: now,
|
||||||
|
// PointId: api.NameDevicePoint(psId, point),
|
||||||
|
// PointGroupName: "Summary",
|
||||||
|
// PointName: name,
|
||||||
|
// Value: value,
|
||||||
|
// Unit: "",
|
||||||
|
// ValueType: vt,
|
||||||
|
// Index: index,
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func addIntValue(now api.DateTime, point string, name string, value int64, unit string, index int) api.DataEntry {
|
||||||
|
return add(now, "virtual", point, name, api.UnitValue{ Value: strconv.FormatInt(value, 10), Unit: unit }, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFloatValue(now api.DateTime, point string, name string, value float64, unit string, index int) api.DataEntry {
|
||||||
|
return add(now, "virtual", point, name, api.UnitValue{ Value: api.Float64ToString(value), Unit: unit }, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(now api.DateTime, psId string, point string, name string, value api.UnitValue, index int) api.DataEntry {
|
||||||
|
vt := api.GetPoint(psId, point)
|
||||||
|
if !vt.Valid {
|
||||||
|
vt = &api.Point{
|
||||||
|
PsKey: psId,
|
||||||
|
Id: point,
|
||||||
|
Description: name,
|
||||||
|
Unit: value.Unit,
|
||||||
|
Type: "PointTypeInstant",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return api.DataEntry {
|
||||||
|
Date: now,
|
||||||
|
PointId: api.NameDevicePoint(psId, point),
|
||||||
|
PointGroupName: "Virtual",
|
||||||
|
PointName: name,
|
||||||
|
Value: value.Value,
|
||||||
|
Unit: value.Unit,
|
||||||
|
ValueType: vt,
|
||||||
|
Index: index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func addState(now api.DateTime, point string, name string, state bool, index int) api.DataEntry {
|
||||||
|
// return api.DataEntry {
|
||||||
|
// Date: now,
|
||||||
|
// PointId: api.NameDevicePoint("virtual", point),
|
||||||
|
// PointGroupName: "Virtual",
|
||||||
|
// PointName: name,
|
||||||
|
// Value: fmt.Sprintf("%v", state),
|
||||||
|
// Unit: "binary",
|
||||||
|
// ValueType: &api.Point{
|
||||||
|
// PsKey: "virtual",
|
||||||
|
// Id: point,
|
||||||
|
// Description: name,
|
||||||
|
// Unit: "binary",
|
||||||
|
// Type: "PointTypeInstant",
|
||||||
|
// },
|
||||||
|
// Index: index,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
func isActive(value float64) bool {
|
||||||
|
if (value > 0.01) || (value < -0.01) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
@ -24,6 +24,7 @@ type Point struct {
|
|||||||
Description string
|
Description string
|
||||||
Unit string
|
Unit string
|
||||||
Type string
|
Type string
|
||||||
|
Valid bool
|
||||||
}
|
}
|
||||||
type PointsMap map[string]Point
|
type PointsMap map[string]Point
|
||||||
|
|
||||||
@ -292,15 +293,24 @@ func (p Point) String() string {
|
|||||||
func (pm PointsMap) Get(device string, point string) *Point {
|
func (pm PointsMap) Get(device string, point string) *Point {
|
||||||
dp := device + ".p" + strings.TrimPrefix(point, "p")
|
dp := device + ".p" + strings.TrimPrefix(point, "p")
|
||||||
if p, ok := pm[dp]; ok {
|
if p, ok := pm[dp]; ok {
|
||||||
|
p.Valid = true
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
dp = "p" + strings.TrimPrefix(point, "p")
|
dp = "p" + strings.TrimPrefix(point, "p")
|
||||||
if p, ok := pm[dp]; ok {
|
if p, ok := pm[dp]; ok {
|
||||||
|
p.Valid = true
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return &Point {
|
||||||
|
PsKey: device,
|
||||||
|
Id: dp,
|
||||||
|
Description: "",
|
||||||
|
Unit: "",
|
||||||
|
Type: "",
|
||||||
|
Valid: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm PointsMap) GetDevicePoint(devicePoint string) *Point {
|
func (pm PointsMap) GetDevicePoint(devicePoint string) *Point {
|
||||||
@ -372,3 +382,18 @@ type DataEntry struct {
|
|||||||
ValueType *Point `json:"value_type"`
|
ValueType *Point `json:"value_type"`
|
||||||
Index int `json:"index"`
|
Index int `json:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type string
|
||||||
|
// Name string
|
||||||
|
// SubName string
|
||||||
|
//
|
||||||
|
// ParentId string
|
||||||
|
// ParentName string
|
||||||
|
//
|
||||||
|
// UniqueId string
|
||||||
|
// FullName string
|
||||||
|
// Units string
|
||||||
|
// ValueName string
|
||||||
|
// Class string
|
||||||
|
//
|
||||||
|
// Value string
|
@ -311,6 +311,32 @@ func (sg *SunGrow) QueryDevice(psId int64) queryDeviceList.EndPoint {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sg *SunGrow) QueryPs(psId int64) getPsList.EndPoint {
|
||||||
|
var ret getPsList.EndPoint
|
||||||
|
for range Only.Once {
|
||||||
|
if psId == 0 {
|
||||||
|
psId, sg.Error = sg.GetPsId()
|
||||||
|
if sg.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ep = sg.GetByJson("AppService.queryDeviceList", fmt.Sprintf(`{"ps_id":"%d"}`, psId))
|
||||||
|
ep := sg.GetByStruct(
|
||||||
|
"AppService.getPsList",
|
||||||
|
getPsList.RequestData{},
|
||||||
|
time.Second * 60,
|
||||||
|
)
|
||||||
|
// if sg.Error != nil {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
|
||||||
|
ret = getPsList.Assert(ep)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func (sg *SunGrow) GetPointNames() error {
|
func (sg *SunGrow) GetPointNames() error {
|
||||||
for range Only.Once {
|
for range Only.Once {
|
||||||
for _, dt := range getPowerDevicePointNames.DeviceTypes {
|
for _, dt := range getPowerDevicePointNames.DeviceTypes {
|
||||||
@ -540,6 +566,76 @@ func (sg *SunGrow) GetPsId() (int64, error) {
|
|||||||
return ret, sg.Error
|
return ret, sg.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sg *SunGrow) GetPsName() (string, error) {
|
||||||
|
var ret string
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
|
||||||
|
ep := sg.GetByStruct("AppService.getPsList", nil, DefaultCacheTimeout)
|
||||||
|
if ep.IsError() {
|
||||||
|
sg.Error = ep.GetError()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
_getPsList := getPsList.AssertResultData(ep)
|
||||||
|
ret = _getPsList.GetPsName()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, sg.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *SunGrow) GetPsModel() (string, error) {
|
||||||
|
var ret string
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
var psId int64
|
||||||
|
psId, sg.Error = sg.GetPsId()
|
||||||
|
if sg.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := sg.GetByStruct(
|
||||||
|
"AppService.getPsDetailWithPsType",
|
||||||
|
getPsDetailWithPsType.RequestData{PsId: strconv.FormatInt(psId, 10)},
|
||||||
|
DefaultCacheTimeout)
|
||||||
|
if ep.IsError() {
|
||||||
|
sg.Error = ep.GetError()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ep2 := getPsDetailWithPsType.Assert(ep)
|
||||||
|
ret = ep2.GetDeviceName()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, sg.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *SunGrow) GetPsSerial() (string, error) {
|
||||||
|
var ret string
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
var psId int64
|
||||||
|
psId, sg.Error = sg.GetPsId()
|
||||||
|
if sg.Error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := sg.GetByStruct(
|
||||||
|
"AppService.getPsDetailWithPsType",
|
||||||
|
getPsDetailWithPsType.RequestData{PsId: strconv.FormatInt(psId, 10)},
|
||||||
|
DefaultCacheTimeout)
|
||||||
|
if ep.IsError() {
|
||||||
|
sg.Error = ep.GetError()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ep2 := getPsDetailWithPsType.Assert(ep)
|
||||||
|
ret = ep2.GetDeviceSerial()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, sg.Error
|
||||||
|
}
|
||||||
|
|
||||||
func (sg *SunGrow) GetPsKeys() ([]string, error) {
|
func (sg *SunGrow) GetPsKeys() ([]string, error) {
|
||||||
var ret []string
|
var ret []string
|
||||||
|
|
||||||
|
122
mmHa/binary_sensor.go
Normal file
122
mmHa/binary_sensor.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package mmHa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GoSungrow/Only"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func (m *Mqtt) BinarySensorPublishConfig(config EntityConfig) error {
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
if config.Units != "binary" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueTemplate := fmt.Sprintf("{{ value_json.value }}")
|
||||||
|
|
||||||
|
LastReset := m.GetLastReset(config.UniqueId)
|
||||||
|
LastResetValueTemplate := ""
|
||||||
|
if LastReset != "" {
|
||||||
|
LastResetValueTemplate = "{{ value_json.last_reset | as_datetime() }}"
|
||||||
|
}
|
||||||
|
|
||||||
|
device := m.Device
|
||||||
|
device.Name = JoinStrings(m.Device.Name, config.ParentId)
|
||||||
|
device.Connections = [][]string{
|
||||||
|
{ m.Device.Name, JoinStringsForId(m.Device.Name, config.ParentId) },
|
||||||
|
{ JoinStringsForId(m.Device.Name, config.ParentId), JoinStringsForId(m.Device.Name, config.ParentId, config.Name) },
|
||||||
|
}
|
||||||
|
device.Identifiers = []string{ JoinStringsForId(m.Device.Name, config.ParentId) }
|
||||||
|
st := JoinStringsForId(m.Device.Name, config.ParentId, config.Name) // , config.ParentName, config.Name)
|
||||||
|
// UniqueId: JoinStringsForId(m.Device.Name, config.ParentName, config.Name, config.UniqueId),
|
||||||
|
|
||||||
|
payload := BinarySensor {
|
||||||
|
Device: device,
|
||||||
|
Name: JoinStrings(m.Device.Name, config.ParentName, config.FullName),
|
||||||
|
StateTopic: JoinStringsForTopic(m.binarySensorPrefix, st, "state"),
|
||||||
|
StateClass: "measurement",
|
||||||
|
UniqueId: st,
|
||||||
|
UnitOfMeasurement: config.Units,
|
||||||
|
DeviceClass: config.Class,
|
||||||
|
Qos: 0,
|
||||||
|
ForceUpdate: true,
|
||||||
|
ExpireAfter: 0,
|
||||||
|
Encoding: "utf-8",
|
||||||
|
EnabledByDefault: true,
|
||||||
|
LastResetValueTemplate: LastResetValueTemplate,
|
||||||
|
PayloadOn: "true",
|
||||||
|
PayloadOff: "false",
|
||||||
|
ValueTemplate: ValueTemplate,
|
||||||
|
Icon: "mdi:check-circle-outline", // mdi:check-circle-outline | mdi:arrow-right-bold
|
||||||
|
}
|
||||||
|
|
||||||
|
ct := JoinStringsForTopic(m.binarySensorPrefix, st, "config")
|
||||||
|
t := m.client.Publish(ct, 0, true, payload.Json())
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) BinarySensorPublishValue(config EntityConfig) error {
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
if config.Units != "binary" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
st := JoinStringsForId(m.Device.Name, config.ParentId, config.Name)
|
||||||
|
payload := MqttState {
|
||||||
|
LastReset: m.GetLastReset(config.UniqueId),
|
||||||
|
Value: config.Value,
|
||||||
|
}
|
||||||
|
st = JoinStringsForTopic(m.binarySensorPrefix, st, "state")
|
||||||
|
t := m.client.Publish(st, 0, true, payload.Json())
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type BinarySensor struct {
|
||||||
|
Availability *Availability `json:"availability,omitempty" required:"false"`
|
||||||
|
AvailabilityMode string `json:"availability_mode,omitempty" required:"false"`
|
||||||
|
AvailabilityTemplate string `json:"availability_template,omitempty" required:"false"`
|
||||||
|
AvailabilityTopic string `json:"availability_topic,omitempty" required:"false"`
|
||||||
|
Device Device `json:"device,omitempty" required:"false"`
|
||||||
|
DeviceClass string `json:"device_class,omitempty" required:"false"`
|
||||||
|
EnabledByDefault bool `json:"enabled_by_default,omitempty" required:"false"`
|
||||||
|
Encoding string `json:"encoding,omitempty" required:"false"`
|
||||||
|
EntityCategory string `json:"entity_category,omitempty" required:"false"`
|
||||||
|
ExpireAfter int `json:"expire_after,omitempty" required:"false"`
|
||||||
|
ForceUpdate bool `json:"force_update,omitempty" required:"false"`
|
||||||
|
Icon string `json:"icon,omitempty" required:"false"`
|
||||||
|
JsonAttributesTemplate string `json:"json_attributes_template,omitempty" required:"false"`
|
||||||
|
JsonAttributesTopic string `json:"json_attributes_topic,omitempty" required:"false"`
|
||||||
|
LastResetValueTemplate string `json:"last_reset_value_template,omitempty" required:"false"`
|
||||||
|
Name string `json:"name,omitempty" required:"false"`
|
||||||
|
ObjectId string `json:"object_id,omitempty" required:"false"`
|
||||||
|
PayloadAvailable string `json:"payload_available,omitempty" required:"false"`
|
||||||
|
PayloadNotAvailable string `json:"payload_not_available,omitempty" required:"false"`
|
||||||
|
Qos int `json:"qos,omitempty" required:"false"`
|
||||||
|
StateClass string `json:"state_class,omitempty" required:"false"`
|
||||||
|
StateTopic string `json:"state_topic" required:"true"`
|
||||||
|
UniqueId string `json:"unique_id,omitempty" required:"false"`
|
||||||
|
UnitOfMeasurement string `json:"unit_of_measurement,omitempty" required:"false"`
|
||||||
|
ValueTemplate string `json:"value_template,omitempty" required:"false"`
|
||||||
|
|
||||||
|
OffDelay int `json:"off_delay,omitempty" required:"false"`
|
||||||
|
PayloadOff string `json:"pl_off,omitempty" required:"false"`
|
||||||
|
PayloadOn string `json:"pl_on,omitempty" required:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *BinarySensor) Json() string {
|
||||||
|
j, _ := json.Marshal(*c)
|
||||||
|
return string(j)
|
||||||
|
}
|
@ -1,24 +1,8 @@
|
|||||||
package mmMqtt
|
package mmHa
|
||||||
|
|
||||||
import "encoding/json"
|
import "encoding/json"
|
||||||
|
|
||||||
|
|
||||||
// {
|
|
||||||
// "device": {
|
|
||||||
// "identifiers": [
|
|
||||||
// "sungrow"
|
|
||||||
// ],
|
|
||||||
// "manufacturer": "MickMake",
|
|
||||||
// "model": "GoLang",
|
|
||||||
// "name": "sungrow",
|
|
||||||
// "sw_version": "sungrow https://github.com/MickMake/GoSungrow"
|
|
||||||
// },
|
|
||||||
// "name": "sungrow",
|
|
||||||
// "stat_t": "~/state",
|
|
||||||
// "unique_id": "sungrow",
|
|
||||||
// "~": "homeassistant/binary_sensor/SunGrow"
|
|
||||||
// }
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Entry string `json:"~,omitempty" required:"false"`
|
Entry string `json:"~,omitempty" required:"false"`
|
||||||
Name string `json:"name,omitempty" required:"false"`
|
Name string `json:"name,omitempty" required:"false"`
|
||||||
@ -51,3 +35,19 @@ type Device struct {
|
|||||||
SwVersion string `json:"sw_version,omitempty" required:"false"`
|
SwVersion string `json:"sw_version,omitempty" required:"false"`
|
||||||
ViaDevice string `json:"via_device,omitempty" required:"false"`
|
ViaDevice string `json:"via_device,omitempty" required:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "device": {
|
||||||
|
// "identifiers": [
|
||||||
|
// "sungrow"
|
||||||
|
// ],
|
||||||
|
// "manufacturer": "MickMake",
|
||||||
|
// "model": "GoLang",
|
||||||
|
// "name": "sungrow",
|
||||||
|
// "sw_version": "sungrow https://github.com/MickMake/GoSungrow"
|
||||||
|
// },
|
||||||
|
// "name": "sungrow",
|
||||||
|
// "stat_t": "~/state",
|
||||||
|
// "unique_id": "sungrow",
|
||||||
|
// "~": "homeassistant/binary_sensor/SunGrow"
|
||||||
|
// }
|
1
mmHa/cron.go
Normal file
1
mmHa/cron.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package mmHa
|
@ -1,4 +1,51 @@
|
|||||||
package mmMqtt
|
package mmHa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func JoinStrings(args ...string) string {
|
||||||
|
return strings.TrimSpace(strings.Join(args, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func JoinStringsForId(args ...string) string {
|
||||||
|
var newargs []string
|
||||||
|
var re = regexp.MustCompile(`(/| |:|\.)+`)
|
||||||
|
for _, a := range args {
|
||||||
|
if a == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
a = strings.TrimSpace(a)
|
||||||
|
a = re.ReplaceAllString(a, `_`)
|
||||||
|
newargs = append(newargs, a)
|
||||||
|
}
|
||||||
|
// return strings.ReplaceAll(strings.TrimSpace(strings.Join(args, ".")), ".", "_")
|
||||||
|
return strings.Join(newargs, "-")
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (c *Config) JoinStringsForId() string {
|
||||||
|
// return JoinStringsForId(m.Device.FullName, c.ParentName, c.FullName)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func JoinStringsForTopic(args ...string) string {
|
||||||
|
var newargs []string
|
||||||
|
var re = regexp.MustCompile(`( |:)+`)
|
||||||
|
for _, a := range args {
|
||||||
|
if a == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
a = strings.TrimSpace(a)
|
||||||
|
a = re.ReplaceAllString(a, `_`)
|
||||||
|
newargs = append(newargs, a)
|
||||||
|
}
|
||||||
|
// return strings.ReplaceAll(strings.TrimSpace(strings.Join(args, ".")), ".", "_")
|
||||||
|
return strings.Join(newargs, "/")
|
||||||
|
|
||||||
|
// ret := strings.ReplaceAll(strings.Join(args, "/"), "//", "/")
|
||||||
|
// return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// const DiscoveryPrefix = "homeassistant"
|
// const DiscoveryPrefix = "homeassistant"
|
@ -1,4 +1,61 @@
|
|||||||
package mmMqtt
|
package mmHa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GoSungrow/Only"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishLightConfig(id string, name string, subName string, units string, valueName string, class string) error {
|
||||||
|
for range Only.Once {
|
||||||
|
id = JoinStringsForId(m.EntityPrefix, m.Device.Name, id)
|
||||||
|
|
||||||
|
payload := Light {
|
||||||
|
Device: m.Device,
|
||||||
|
Name: JoinStrings(m.Device.ViaDevice, name),
|
||||||
|
StateTopic: JoinStringsForTopic(m.switchPrefix, id, "state"),
|
||||||
|
// StateClass: "measurement",
|
||||||
|
// UniqueId: id,
|
||||||
|
// UnitOfMeasurement: units,
|
||||||
|
// DeviceClass: class,
|
||||||
|
// Qos: 0,
|
||||||
|
// ForceUpdate: true,
|
||||||
|
// ExpireAfter: 0,
|
||||||
|
// Encoding: "utf-8",
|
||||||
|
// EnabledByDefault: true,
|
||||||
|
// LastResetValueTemplate: LastResetValueTemplate,
|
||||||
|
// LastReset: LastReset,
|
||||||
|
// ValueTemplate: "{{ value_json.value | float }}",
|
||||||
|
// LastReset: time.Now().Format("2006-01-02T00:00:00+00:00"),
|
||||||
|
// LastResetValueTemplate: "{{entity_id}}",
|
||||||
|
// LastResetValueTemplate: "{{ (as_datetime((value_json.last_reset | int | timestamp_utc)|string+'Z')).isoformat() }}",
|
||||||
|
}
|
||||||
|
|
||||||
|
m.client.Publish(JoinStringsForTopic(m.lightPrefix, id, "config"), 0, true, payload.Json())
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishLight(subtopic string, payload interface{}) error {
|
||||||
|
for range Only.Once {
|
||||||
|
t := m.client.Publish(JoinStringsForTopic(m.lightPrefix, subtopic), 0, true, payload)
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishLightState(topic string, payload interface{}) error {
|
||||||
|
for range Only.Once {
|
||||||
|
topic = JoinStringsForId(m.EntityPrefix, m.Device.Name, topic)
|
||||||
|
t := m.client.Publish(JoinStringsForTopic(m.lightPrefix, topic, "state"), 0, true, payload)
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
type Light struct {
|
type Light struct {
|
||||||
@ -74,6 +131,11 @@ type Light struct {
|
|||||||
// messageHandler mqtt.MessageHandler
|
// messageHandler mqtt.MessageHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Light) Json() string {
|
||||||
|
j, _ := json.Marshal(*c)
|
||||||
|
return string(j)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// "brightness": true,
|
// "brightness": true,
|
293
mmHa/sensors.go
Normal file
293
mmHa/sensors.go
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
package mmHa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GoSungrow/Only"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// func (m *Mqtt) PublishSensorConfig(config EntityConfig) error {
|
||||||
|
// // func (m *Mqtt) PublishSensorConfig(id string, name string, subName string, units string, valueName string, class string) error {
|
||||||
|
// for range Only.Once {
|
||||||
|
// // name = strings.ReplaceAll(name, "/", ".")
|
||||||
|
// // config.SubName = strings.ReplaceAll(config.SubName, "/", ".")
|
||||||
|
// // id = JoinStringsForId(m.Device.FullName, config.SubName, id)
|
||||||
|
// // st := JoinStringsForTopic(m.sensorPrefix, JoinStringsForId(m.EntityPrefix, m.Device.FullName, strings.ReplaceAll(config.SubName, "/", ".")), "state")
|
||||||
|
// // st := m.GetSensorStateTopic(name, config.SubName)
|
||||||
|
//
|
||||||
|
// device := m.Device
|
||||||
|
// device.Name = JoinStrings(m.Device.Name, config.ParentId)
|
||||||
|
// device.Connections = [][]string{{m.Device.Name, device.Name}}
|
||||||
|
// device.Identifiers = []string{device.Name}
|
||||||
|
// st := JoinStringsForId(m.Device.Name, config.ParentName, config.Name)
|
||||||
|
//
|
||||||
|
// payload := Sensor {
|
||||||
|
// Device: device,
|
||||||
|
// DeviceClass: config.Class,
|
||||||
|
// Name: JoinStrings(m.Device.Name, config.ParentName, config.Name, config.SubName), // config.FullName, // JoinStrings(m.Device.ViaDevice, config.SubName),
|
||||||
|
// StateTopic: JoinStringsForTopic(m.sensorPrefix, st, "state"), // m.GetSensorStateTopic(name, config.SubName),m.EntityPrefix, m.Device.FullName, config.SubName
|
||||||
|
// StateClass: "measurement",
|
||||||
|
// UniqueId: JoinStringsForId(m.Device.Name, config.ParentName, config.Name, config.UniqueId),
|
||||||
|
// UnitOfMeasurement: config.Units,
|
||||||
|
// Qos: 0,
|
||||||
|
// ForceUpdate: true,
|
||||||
|
// ExpireAfter: 0,
|
||||||
|
// Encoding: "utf-8",
|
||||||
|
// EnabledByDefault: true,
|
||||||
|
// // LastResetValueTemplate: LastResetValueTemplate,
|
||||||
|
// // LastReset: LastReset,
|
||||||
|
// // "{%if is_state(value_json.ifadminstatus,\"up\")-%}ON{%-else-%}OFF{%-endif%}"
|
||||||
|
// ValueTemplate: fmt.Sprintf("{{ value_json.%s | is_defined }}", config.ValueName),
|
||||||
|
// // LastReset: time.Now().Format("2006-01-02T00:00:00+00:00"),
|
||||||
|
// // LastResetValueTemplate: "{{entity_id}}",
|
||||||
|
// // LastResetValueTemplate: "{{ (as_datetime((value_json.last_reset | int | timestamp_utc)|string+'Z')).isoformat() }}",
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ct := JoinStringsForId(m.Device.Name, config.ParentName, config.Name, config.SubName)
|
||||||
|
// m.client.Publish(JoinStringsForTopic(m.sensorPrefix, ct, "config"), 0, true, payload.Json())
|
||||||
|
// // m.client.Publish(JoinStringsForTopic(m.sensorPrefix, config.UniqueId, "config"), 0, true, payload.Json())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
|
||||||
|
type Fields map[string]string
|
||||||
|
func (m *Mqtt) PublishSensorValues(configs []EntityConfig) error {
|
||||||
|
for range Only.Once {
|
||||||
|
cs := make(map[string]Fields)
|
||||||
|
topic := ""
|
||||||
|
for _, oid := range configs {
|
||||||
|
if topic == "" {
|
||||||
|
topic = JoinStringsForId(m.Device.Name, oid.ParentName, oid.Name)
|
||||||
|
}
|
||||||
|
if _, ok := cs[oid.Type]; !ok {
|
||||||
|
cs[oid.Type] = make(Fields)
|
||||||
|
}
|
||||||
|
cs[oid.Type][oid.ValueName] = oid.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
for n, c := range cs {
|
||||||
|
j, _ := json.Marshal(c)
|
||||||
|
fmt.Printf("%s (%s) -> %s\n", topic, n, string(j))
|
||||||
|
|
||||||
|
m.err = m.PublishValue(n, topic, string(j))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) GetSensorStateTopic(config EntityConfig) string {
|
||||||
|
st := JoinStringsForId(m.Device.Name, config.ParentName, config.Name)
|
||||||
|
st = JoinStringsForTopic(m.sensorPrefix, st, "state") // m.GetSensorStateTopic(name, config.SubName),m.EntityPrefix, m.Device.FullName, config.SubName
|
||||||
|
return st
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) SensorPublishConfig(config EntityConfig) error {
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
if config.Units == "binary" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueTemplate := "{{ value_json.value | float }}"
|
||||||
|
// ValueTemplate := fmt.Sprintf("{{ value_json.%s | float }}", config.ValueName) // <- Used with merged values.
|
||||||
|
|
||||||
|
LastReset := m.GetLastReset(config.UniqueId)
|
||||||
|
LastResetValueTemplate := ""
|
||||||
|
if LastReset != "" {
|
||||||
|
LastResetValueTemplate = "{{ value_json.last_reset | as_datetime() }}"
|
||||||
|
// LastResetValueTemplate = "{{ value_json.last_reset | int | timestamp_local | as_datetime }}"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch config.Units {
|
||||||
|
case "MW":
|
||||||
|
fallthrough
|
||||||
|
case "kW":
|
||||||
|
fallthrough
|
||||||
|
case "W":
|
||||||
|
config.Class = "power"
|
||||||
|
|
||||||
|
case "MWh":
|
||||||
|
fallthrough
|
||||||
|
case "kWh":
|
||||||
|
fallthrough
|
||||||
|
case "Wh":
|
||||||
|
config.Class = "energy"
|
||||||
|
|
||||||
|
case "kvar":
|
||||||
|
config.Class = "reactive_power"
|
||||||
|
|
||||||
|
case "Hz":
|
||||||
|
config.Class = "frequency"
|
||||||
|
|
||||||
|
case "V":
|
||||||
|
config.Class = "voltage"
|
||||||
|
|
||||||
|
case "A":
|
||||||
|
config.Class = "current"
|
||||||
|
|
||||||
|
case "℃":
|
||||||
|
config.Class = "temperature"
|
||||||
|
// point.Unit = "C"
|
||||||
|
|
||||||
|
case "C":
|
||||||
|
config.Class = "temperature"
|
||||||
|
config.Units = "℃"
|
||||||
|
|
||||||
|
case "%":
|
||||||
|
config.Class = "battery"
|
||||||
|
|
||||||
|
default:
|
||||||
|
ValueTemplate = "{{ value_json.value }}"
|
||||||
|
}
|
||||||
|
|
||||||
|
device := m.Device
|
||||||
|
device.Name = JoinStrings(m.Device.Name, config.ParentId)
|
||||||
|
device.Connections = [][]string {
|
||||||
|
{ m.Device.Name, JoinStringsForId(m.Device.Name, config.ParentId) },
|
||||||
|
{ JoinStringsForId(m.Device.Name, config.ParentId), JoinStringsForId(m.Device.Name, config.ParentId, config.Name) },
|
||||||
|
}
|
||||||
|
device.Identifiers = []string{ JoinStringsForId(m.Device.Name, config.ParentId) }
|
||||||
|
st := JoinStringsForId(m.Device.Name, config.ParentId, config.Name) // , config.ParentName, config.Name)
|
||||||
|
// UniqueId: JoinStringsForId(m.Device.Name, config.ParentName, config.Name, config.UniqueId),
|
||||||
|
|
||||||
|
payload := Sensor {
|
||||||
|
Device: device,
|
||||||
|
Name: JoinStrings(m.Device.Name, config.ParentName, config.FullName),
|
||||||
|
StateTopic: JoinStringsForTopic(m.sensorPrefix, st, "state"),
|
||||||
|
// m.GetSensorStateTopic(name, config.SubName),m.EntityPrefix, m.Device.FullName, config.SubName
|
||||||
|
StateClass: "measurement",
|
||||||
|
UniqueId: st,
|
||||||
|
UnitOfMeasurement: config.Units,
|
||||||
|
DeviceClass: config.Class,
|
||||||
|
Qos: 0,
|
||||||
|
ForceUpdate: true,
|
||||||
|
ExpireAfter: 0,
|
||||||
|
Encoding: "utf-8",
|
||||||
|
EnabledByDefault: true,
|
||||||
|
LastResetValueTemplate: LastResetValueTemplate,
|
||||||
|
LastReset: LastReset,
|
||||||
|
ValueTemplate: ValueTemplate,
|
||||||
|
}
|
||||||
|
|
||||||
|
ct := JoinStringsForTopic(m.sensorPrefix, st, "config")
|
||||||
|
t := m.client.Publish(ct, 0, true, payload.Json())
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// func (m *Mqtt) PublishSensor(subtopic string, payload interface{}) error {
|
||||||
|
// for range Only.Once {
|
||||||
|
// t := m.client.Publish(subtopic, 0, true, payload)
|
||||||
|
// if !t.WaitTimeout(m.Timeout) {
|
||||||
|
// m.err = t.Error()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
// func (m *Mqtt) SensorPublish(subtopic string, payload interface{}) error {
|
||||||
|
// for range Only.Once {
|
||||||
|
// m.client.Publish(SensorBaseTopic + "/" + subtopic, 0, true, payload)
|
||||||
|
// }
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (m *Mqtt) PublishSensorState(topic string, payload interface{}) error {
|
||||||
|
// for range Only.Once {
|
||||||
|
// // topic = JoinStringsForId(m.EntityPrefix, m.Device.Name, topic)
|
||||||
|
// // topic = JoinStringsForTopic(m.sensorPrefix, topic, "state")
|
||||||
|
// // st := JoinStringsForTopic(m.sensorPrefix, JoinStringsForId(m.EntityPrefix, m.Device.FullName, strings.ReplaceAll(subName, "/", ".")), "state")
|
||||||
|
// t := m.client.Publish(topic, 0, true, payload)
|
||||||
|
// if !t.WaitTimeout(m.Timeout) {
|
||||||
|
// m.err = t.Error()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
// func (m *Mqtt) SensorPublishState(id string, payload interface{}) error {
|
||||||
|
// for range Only.Once {
|
||||||
|
// id = strings.ReplaceAll("sungrow_" + id, ".", "-")
|
||||||
|
// m.client.Publish(SensorBaseTopic + "/" + id + "/state", 0, true, payload)
|
||||||
|
// }
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (m *Mqtt) PublishSensorValue(topic string, value string) error {
|
||||||
|
// for range Only.Once {
|
||||||
|
// topic = JoinStringsForId(m.EntityPrefix, m.Device.Name, topic)
|
||||||
|
// // st := JoinStringsForTopic(m.sensorPrefix, JoinStringsForId(m.EntityPrefix, m.Device.FullName, strings.ReplaceAll(subName, "/", ".")), "state")
|
||||||
|
// payload := MqttState {
|
||||||
|
// LastReset: "", // m.GetLastReset(point.PointId),
|
||||||
|
// Value: value,
|
||||||
|
// }
|
||||||
|
// m.client.Publish(JoinStringsForTopic(m.sensorPrefix, topic, "state"), 0, true, payload.Json())
|
||||||
|
// }
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (m *Mqtt) SensorPublishValue(config EntityConfig) error {
|
||||||
|
// func (m *Mqtt) SensorPublishValue(point api.DataEntry) error {
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
if config.Units == "binary" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
st := JoinStringsForId(m.Device.Name, config.ParentId, config.Name)
|
||||||
|
payload := MqttState {
|
||||||
|
LastReset: m.GetLastReset(config.UniqueId),
|
||||||
|
Value: config.Value,
|
||||||
|
}
|
||||||
|
st = JoinStringsForTopic(m.sensorPrefix, st, "state")
|
||||||
|
t := m.client.Publish(st, 0, true, payload.Json())
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Sensor struct {
|
||||||
|
Availability *Availability `json:"availability,omitempty" required:"false"`
|
||||||
|
AvailabilityMode string `json:"availability_mode,omitempty" required:"false"`
|
||||||
|
AvailabilityTemplate string `json:"availability_template,omitempty" required:"false"`
|
||||||
|
AvailabilityTopic string `json:"availability_topic,omitempty" required:"false"`
|
||||||
|
Device Device `json:"device,omitempty" required:"false"`
|
||||||
|
DeviceClass string `json:"device_class,omitempty" required:"false"`
|
||||||
|
EnabledByDefault bool `json:"enabled_by_default,omitempty" required:"false"`
|
||||||
|
Encoding string `json:"encoding,omitempty" required:"false"`
|
||||||
|
EntityCategory string `json:"entity_category,omitempty" required:"false"`
|
||||||
|
ExpireAfter int `json:"expire_after,omitempty" required:"false"`
|
||||||
|
ForceUpdate bool `json:"force_update,omitempty" required:"false"`
|
||||||
|
Icon string `json:"icon,omitempty" required:"false"`
|
||||||
|
JsonAttributesTemplate string `json:"json_attributes_template,omitempty" required:"false"`
|
||||||
|
JsonAttributesTopic string `json:"json_attributes_topic,omitempty" required:"false"`
|
||||||
|
LastResetValueTemplate string `json:"last_reset_value_template,omitempty" required:"false"`
|
||||||
|
Name string `json:"name,omitempty" required:"false"`
|
||||||
|
ObjectId string `json:"object_id,omitempty" required:"false"`
|
||||||
|
PayloadAvailable string `json:"payload_available,omitempty" required:"false"`
|
||||||
|
PayloadNotAvailable string `json:"payload_not_available,omitempty" required:"false"`
|
||||||
|
Qos int `json:"qos,omitempty" required:"false"`
|
||||||
|
StateClass string `json:"state_class,omitempty" required:"false"`
|
||||||
|
StateTopic string `json:"state_topic" required:"true"`
|
||||||
|
UniqueId string `json:"unique_id,omitempty" required:"false"`
|
||||||
|
UnitOfMeasurement string `json:"unit_of_measurement,omitempty" required:"false"`
|
||||||
|
ValueTemplate string `json:"value_template,omitempty" required:"false"`
|
||||||
|
LastReset string `json:"last_reset,omitempty" required:"false"`
|
||||||
|
|
||||||
|
// StateFunc func() string `json:"-"`
|
||||||
|
//
|
||||||
|
// UpdateInterval float64 `json:"-"`
|
||||||
|
// ForceUpdateMQTT bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sensor) Json() string {
|
||||||
|
j, _ := json.Marshal(*c)
|
||||||
|
return string(j)
|
||||||
|
}
|
460
mmHa/struct.go
Normal file
460
mmHa/struct.go
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
package mmHa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GoSungrow/Only"
|
||||||
|
"GoSungrow/iSolarCloud/api"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type Mqtt struct {
|
||||||
|
ClientId string `json:"client_id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port string `json:"port"`
|
||||||
|
Timeout time.Duration `json:"timeout"`
|
||||||
|
EntityPrefix string `json:"entity_prefix"`
|
||||||
|
|
||||||
|
url *url.URL
|
||||||
|
client mqtt.Client
|
||||||
|
pubClient mqtt.Client
|
||||||
|
clientOptions *mqtt.ClientOptions
|
||||||
|
LastRefresh time.Time `json:"-"`
|
||||||
|
PsId int64 `json:"-"`
|
||||||
|
|
||||||
|
Device Device
|
||||||
|
|
||||||
|
servicePrefix string
|
||||||
|
sensorPrefix string
|
||||||
|
lightPrefix string
|
||||||
|
switchPrefix string
|
||||||
|
binarySensorPrefix string
|
||||||
|
|
||||||
|
token mqtt.Token
|
||||||
|
firstRun bool
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(req Mqtt) *Mqtt {
|
||||||
|
var ret Mqtt
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
ret.err = ret.setUrl(req)
|
||||||
|
if ret.err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ret.firstRun = true
|
||||||
|
ret.EntityPrefix = req.EntityPrefix
|
||||||
|
|
||||||
|
ret.servicePrefix = "homeassistant/sensor/" + req.ClientId
|
||||||
|
ret.sensorPrefix = "homeassistant/sensor/" + req.ClientId
|
||||||
|
ret.lightPrefix = "homeassistant/light/" + req.ClientId
|
||||||
|
ret.switchPrefix = "homeassistant/switch/" + req.ClientId
|
||||||
|
ret.binarySensorPrefix = "homeassistant/binary_sensor/" + req.ClientId
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) IsFirstRun() bool {
|
||||||
|
return m.firstRun
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) IsNotFirstRun() bool {
|
||||||
|
return !m.firstRun
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) UnsetFirstRun() {
|
||||||
|
m.firstRun = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) GetError() error {
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) IsError() bool {
|
||||||
|
if m.err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) IsNewDay() bool {
|
||||||
|
var yes bool
|
||||||
|
for range Only.Once {
|
||||||
|
last := m.LastRefresh.Format("20060102")
|
||||||
|
now := time.Now().Format("20060102")
|
||||||
|
|
||||||
|
if last != now {
|
||||||
|
yes = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return yes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) setUrl(req Mqtt) error {
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
// if req.Username == "" {
|
||||||
|
// m.err = errors.New("username empty")
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
m.Username = req.Username
|
||||||
|
|
||||||
|
// if req.Password == "" {
|
||||||
|
// m.err = errors.New("password empty")
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
m.Password = req.Password
|
||||||
|
|
||||||
|
if req.Host == "" {
|
||||||
|
m.err = errors.New("HASSIO mqtt host not defined")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
m.Host = req.Host
|
||||||
|
|
||||||
|
if req.Port == "" {
|
||||||
|
req.Port = "1883"
|
||||||
|
}
|
||||||
|
m.Port = req.Port
|
||||||
|
|
||||||
|
u := fmt.Sprintf("tcp://%s:%s@%s:%s",
|
||||||
|
m.Username,
|
||||||
|
m.Password,
|
||||||
|
m.Host,
|
||||||
|
m.Port,
|
||||||
|
)
|
||||||
|
m.url, m.err = url.Parse(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) SetAuth(username string, password string) error {
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
if username == "" {
|
||||||
|
m.err = errors.New("username empty")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
m.Username = username
|
||||||
|
|
||||||
|
if password == "" {
|
||||||
|
m.err = errors.New("password empty")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
m.Password = password
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) Connect() error {
|
||||||
|
for range Only.Once {
|
||||||
|
m.err = m.createClientOptions()
|
||||||
|
if m.err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
m.client = mqtt.NewClient(m.clientOptions)
|
||||||
|
token := m.client.Connect()
|
||||||
|
for !token.WaitTimeout(3 * time.Second) {
|
||||||
|
}
|
||||||
|
if m.err = token.Error(); m.err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if m.ClientId == "" {
|
||||||
|
m.ClientId = "GoSunGrow"
|
||||||
|
}
|
||||||
|
|
||||||
|
device := Config {
|
||||||
|
Entry: m.servicePrefix,
|
||||||
|
Name: m.ClientId,
|
||||||
|
UniqueId: m.ClientId, // + "_Service",
|
||||||
|
StateTopic: "~/state",
|
||||||
|
DeviceConfig: DeviceConfig {
|
||||||
|
Identifiers: []string{"GoSunGrow"},
|
||||||
|
SwVersion: "GoSunGrow https://github.com/MickMake/GoSungrow",
|
||||||
|
Name: m.ClientId + " Service",
|
||||||
|
Manufacturer: "MickMake",
|
||||||
|
Model: "SunGrow",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
m.err = m.Publish(JoinStringsForTopic(m.servicePrefix, "config"), 0, true, device.Json())
|
||||||
|
if m.err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
m.err = m.Publish(JoinStringsForTopic(m.servicePrefix, "state"), 0, true, "ON")
|
||||||
|
if m.err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) Disconnect() error {
|
||||||
|
for range Only.Once {
|
||||||
|
m.client.Disconnect(250)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// const ServiceBaseName = "GoSunGrow"
|
||||||
|
// const ServiceBaseUniqueId = ServiceBaseName + "_Service"
|
||||||
|
// const ServiceBaseTopic = "homeassistant/sensor/" + ServiceBaseName
|
||||||
|
// const SensorBaseTopic = "homeassistant/sensor/" + ServiceBaseName
|
||||||
|
|
||||||
|
func (m *Mqtt) createClientOptions() error {
|
||||||
|
for range Only.Once {
|
||||||
|
m.clientOptions = mqtt.NewClientOptions()
|
||||||
|
m.clientOptions.AddBroker(fmt.Sprintf("tcp://%s", m.url.Host))
|
||||||
|
m.clientOptions.SetUsername(m.url.User.Username())
|
||||||
|
password, _ := m.url.User.Password()
|
||||||
|
m.clientOptions.SetPassword(password)
|
||||||
|
m.clientOptions.SetClientID(m.ClientId)
|
||||||
|
|
||||||
|
m.clientOptions.WillTopic = JoinStringsForTopic(m.servicePrefix, "state")
|
||||||
|
m.clientOptions.WillPayload = []byte("OFF")
|
||||||
|
m.clientOptions.WillQos = 0
|
||||||
|
m.clientOptions.WillRetained = true
|
||||||
|
m.clientOptions.WillEnabled = true
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) Subscribe(topic string) error {
|
||||||
|
for range Only.Once {
|
||||||
|
t := m.client.Subscribe(topic, 0, func(client mqtt.Client, msg mqtt.Message) {
|
||||||
|
fmt.Printf("* [%s] %s\n", msg.Topic(), string(msg.Payload()))
|
||||||
|
})
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
// m.err = errors.New("mqtt subscribe timeout")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) Publish(topic string, qos byte, retained bool, payload interface{}) error {
|
||||||
|
for range Only.Once {
|
||||||
|
t := m.client.Publish(topic, qos, retained, payload)
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
// m.err = errors.New("mqtt publish timeout")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// func (m *Mqtt) PublishConfig(config EntityConfig) error {
|
||||||
|
// // func (m *Mqtt) PublishConfig(t string, id string, name string, subName string, units string, valueName string, class string) error {
|
||||||
|
// switch config.Type {
|
||||||
|
// // case "sensor":
|
||||||
|
// // m.err = m.PublishSensorConfig(id, name, subName, units, valueName, class)
|
||||||
|
// case "binary_sensor":
|
||||||
|
// m.err = m.PublishBinarySensorConfig(config) // (id, name, subName, units, valueName, class)
|
||||||
|
// // case "lights":
|
||||||
|
// // m.err = m.PublishLightConfig(id, name, subName, units, valueName, class)
|
||||||
|
// // case "switch":
|
||||||
|
// // m.err = m.PublishSwitchConfig(id, name, subName, units, valueName, class)
|
||||||
|
// // default:
|
||||||
|
// // m.err = m.PublishSensorConfig(config)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishState(Type string, subtopic string, payload interface{}) error {
|
||||||
|
for range Only.Once {
|
||||||
|
// topic = JoinStringsForId(m.EntityPrefix, m.Device.Name, topic)
|
||||||
|
// topic = JoinStringsForTopic(m.sensorPrefix, topic, "state")
|
||||||
|
// st := JoinStringsForTopic(m.sensorPrefix, JoinStringsForId(m.EntityPrefix, m.Device.FullName, strings.ReplaceAll(subName, "/", ".")), "state")
|
||||||
|
topic := ""
|
||||||
|
switch Type {
|
||||||
|
case "sensor":
|
||||||
|
topic = JoinStringsForTopic(m.sensorPrefix, subtopic, "state")
|
||||||
|
case "binary_sensor":
|
||||||
|
topic = JoinStringsForTopic(m.binarySensorPrefix, subtopic, "state")
|
||||||
|
case "lights":
|
||||||
|
topic = JoinStringsForTopic(m.lightPrefix, subtopic, "state")
|
||||||
|
case "switch":
|
||||||
|
topic = JoinStringsForTopic(m.switchPrefix, subtopic, "state")
|
||||||
|
default:
|
||||||
|
topic = JoinStringsForTopic(m.sensorPrefix, subtopic, "state")
|
||||||
|
}
|
||||||
|
|
||||||
|
t := m.client.Publish(topic, 0, true, payload)
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishValue(Type string, subtopic string, value string) error {
|
||||||
|
for range Only.Once {
|
||||||
|
topic := ""
|
||||||
|
switch Type {
|
||||||
|
case "sensor":
|
||||||
|
topic = JoinStringsForTopic(m.sensorPrefix, subtopic, "state")
|
||||||
|
// state := MqttState {
|
||||||
|
// LastReset: "", // m.GetLastReset(point.PointId),
|
||||||
|
// Value: value,
|
||||||
|
// }
|
||||||
|
// value = state.Json()
|
||||||
|
|
||||||
|
case "binary_sensor":
|
||||||
|
topic = JoinStringsForTopic(m.binarySensorPrefix, subtopic, "state")
|
||||||
|
// state := MqttState {
|
||||||
|
// LastReset: "", // m.GetLastReset(point.PointId),
|
||||||
|
// Value: value,
|
||||||
|
// }
|
||||||
|
// value = state.Json()
|
||||||
|
|
||||||
|
case "lights":
|
||||||
|
topic = JoinStringsForTopic(m.lightPrefix, subtopic, "state")
|
||||||
|
// state := MqttState {
|
||||||
|
// LastReset: "", // m.GetLastReset(point.PointId),
|
||||||
|
// Value: value,
|
||||||
|
// }
|
||||||
|
// value = state.Json()
|
||||||
|
|
||||||
|
case "switch":
|
||||||
|
topic = JoinStringsForTopic(m.switchPrefix, subtopic, "state")
|
||||||
|
// state := MqttState {
|
||||||
|
// LastReset: "", // m.GetLastReset(point.PointId),
|
||||||
|
// Value: value,
|
||||||
|
// }
|
||||||
|
// value = state.Json()
|
||||||
|
|
||||||
|
default:
|
||||||
|
topic = JoinStringsForTopic(m.sensorPrefix, subtopic, "state")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t = JoinStringsForId(m.EntityPrefix, m.Device.Name, t)
|
||||||
|
// st := JoinStringsForTopic(m.sensorPrefix, JoinStringsForId(m.EntityPrefix, m.Device.FullName, strings.ReplaceAll(subName, "/", ".")), "state")
|
||||||
|
// payload := MqttState {
|
||||||
|
// LastReset: "", // m.GetLastReset(point.PointId),
|
||||||
|
// Value: value,
|
||||||
|
// }
|
||||||
|
// m.client.Publish(JoinStringsForTopic(m.sensorPrefix, t, "state"), 0, true, payload.Json())
|
||||||
|
t := m.client.Publish(topic, 0, true, value)
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (m *Mqtt) PublishValue(t string, topic string, value string) error {
|
||||||
|
// switch t {
|
||||||
|
// case "sensor":
|
||||||
|
// m.err = m.PublishSensorValue(topic, value)
|
||||||
|
// case "binary_sensor":
|
||||||
|
// m.err = m.PublishBinarySensorState(topic, value)
|
||||||
|
// case "lights":
|
||||||
|
// m.err = m.PublishLightState(topic, value)
|
||||||
|
// case "switch":
|
||||||
|
// m.err = m.PublishSwitchState(topic, value)
|
||||||
|
// default:
|
||||||
|
// m.err = m.PublishSensorState(topic, value)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return m.err
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (m *Mqtt) SetDeviceConfig(swname string, id string, name string, model string, vendor string, area string) error {
|
||||||
|
for range Only.Once {
|
||||||
|
id = JoinStringsForId(m.EntityPrefix, id)
|
||||||
|
|
||||||
|
m.Device = Device {
|
||||||
|
Connections: [][]string{
|
||||||
|
{swname, id},
|
||||||
|
},
|
||||||
|
Identifiers: []string{id},
|
||||||
|
Manufacturer: vendor,
|
||||||
|
Model: model,
|
||||||
|
Name: name,
|
||||||
|
SwVersion: swname + " https://github.com/MickMake/" + swname,
|
||||||
|
ViaDevice: swname,
|
||||||
|
SuggestedArea: area,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type MqttState struct {
|
||||||
|
LastReset string `json:"last_reset,omitempty"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mq *MqttState) Json() string {
|
||||||
|
var ret string
|
||||||
|
for range Only.Once {
|
||||||
|
j, err := json.Marshal(*mq)
|
||||||
|
if err != nil {
|
||||||
|
ret = fmt.Sprintf("{ \"error\": \"%s\"", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ret = string(j)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Availability struct {
|
||||||
|
PayloadAvailable string `json:"payload_available,omitempty" required:"false"`
|
||||||
|
PayloadNotAvailable string `json:"payload_not_available,omitempty" required:"false"`
|
||||||
|
Topic string `json:"topic,omitempty" required:"true"`
|
||||||
|
ValueTemplate string `json:"value_template,omitempty" required:"false"`
|
||||||
|
}
|
||||||
|
type SensorState string
|
||||||
|
|
||||||
|
|
||||||
|
func (m *Mqtt) GetLastReset(pointType string) string {
|
||||||
|
var ret string
|
||||||
|
|
||||||
|
for range Only.Once {
|
||||||
|
pt := api.GetDevicePoint(pointType)
|
||||||
|
if !pt.Valid {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ret = pt.WhenReset()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type EntityConfig struct {
|
||||||
|
Type string
|
||||||
|
Name string
|
||||||
|
SubName string
|
||||||
|
|
||||||
|
ParentId string
|
||||||
|
ParentName string
|
||||||
|
|
||||||
|
UniqueId string
|
||||||
|
FullName string
|
||||||
|
Units string
|
||||||
|
ValueName string
|
||||||
|
Class string
|
||||||
|
Icon string
|
||||||
|
|
||||||
|
Value string
|
||||||
|
}
|
94
mmHa/switch.go
Normal file
94
mmHa/switch.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package mmHa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GoSungrow/Only"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishSwitchConfig(id string, name string, subName string, units string, valueName string, class string) error {
|
||||||
|
for range Only.Once {
|
||||||
|
id = JoinStringsForId(m.EntityPrefix, m.Device.Name, id)
|
||||||
|
|
||||||
|
payload := Switch {
|
||||||
|
Device: m.Device,
|
||||||
|
Name: JoinStrings(m.Device.ViaDevice, name),
|
||||||
|
StateTopic: JoinStringsForTopic(m.switchPrefix, id, "state"),
|
||||||
|
// StateClass: "measurement",
|
||||||
|
// UniqueId: id,
|
||||||
|
// UnitOfMeasurement: units,
|
||||||
|
// DeviceClass: class,
|
||||||
|
// Qos: 0,
|
||||||
|
// ForceUpdate: true,
|
||||||
|
// ExpireAfter: 0,
|
||||||
|
// Encoding: "utf-8",
|
||||||
|
// EnabledByDefault: true,
|
||||||
|
// LastResetValueTemplate: LastResetValueTemplate,
|
||||||
|
// LastReset: LastReset,
|
||||||
|
// ValueTemplate: "{{ value_json.value | float }}",
|
||||||
|
// LastReset: time.Now().Format("2006-01-02T00:00:00+00:00"),
|
||||||
|
// LastResetValueTemplate: "{{entity_id}}",
|
||||||
|
// LastResetValueTemplate: "{{ (as_datetime((value_json.last_reset | int | timestamp_utc)|string+'Z')).isoformat() }}",
|
||||||
|
}
|
||||||
|
|
||||||
|
m.client.Publish(JoinStringsForTopic(m.switchPrefix, id, "config"), 0, true, payload.Json())
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishSwitch(subtopic string, payload interface{}) error {
|
||||||
|
for range Only.Once {
|
||||||
|
t := m.client.Publish(JoinStringsForTopic(m.switchPrefix, subtopic), 0, true, payload)
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mqtt) PublishSwitchState(topic string, payload interface{}) error {
|
||||||
|
for range Only.Once {
|
||||||
|
topic = JoinStringsForId(m.EntityPrefix, m.Device.Name, topic)
|
||||||
|
t := m.client.Publish(JoinStringsForTopic(m.switchPrefix, topic, "state"), 0, true, payload)
|
||||||
|
if !t.WaitTimeout(m.Timeout) {
|
||||||
|
m.err = t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Switch struct {
|
||||||
|
AvailabilityTopic string `json:"avty_t,omitempty"`
|
||||||
|
CommandTopic string `json:"cmd_t"`
|
||||||
|
Device Device `json:"dev,omitempty"`
|
||||||
|
Icon string `json:"ic,omitempty"`
|
||||||
|
JSONAttributesTemplate string `json:"json_attr_tpl,omitempty"`
|
||||||
|
JSONAttributesTopic string `json:"json_attr_t,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Optimistic bool `json:"opt,omitempty"`
|
||||||
|
PayloadAvailable string `json:"pl_avail,omitempty"`
|
||||||
|
PayloadNotAvailable string `json:"pl_not_avail,omitempty"`
|
||||||
|
PayloadOff string `json:"pl_off,omitempty"`
|
||||||
|
PayloadOn string `json:"pl_on,omitempty"`
|
||||||
|
QOS int `json:"qos,omitempty"`
|
||||||
|
Retain bool `json:"ret,omitempty"`
|
||||||
|
StateOff string `json:"stat_off,omitempty"`
|
||||||
|
StateOn string `json:"stat_on,omitempty"`
|
||||||
|
StateTopic string `json:"stat_t,omitempty"`
|
||||||
|
UniqueID string `json:"uniq_id,omitempty"`
|
||||||
|
ValueTemplate string `json:"val_tpl,omitempty"`
|
||||||
|
|
||||||
|
// CommandFunc func(mqtt.Message, mqtt.Client) `json:"-"`
|
||||||
|
// StateFunc func() string `json:"-"`
|
||||||
|
//
|
||||||
|
// UpdateInterval float64 `json:"-"`
|
||||||
|
// ForceUpdateMQTT bool `json:"-"`
|
||||||
|
//
|
||||||
|
// messageHandler mqtt.MessageHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Switch) Json() string {
|
||||||
|
j, _ := json.Marshal(*c)
|
||||||
|
return string(j)
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package mmMqtt
|
|
@ -1,110 +0,0 @@
|
|||||||
package mmMqtt
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
|
|
||||||
// {
|
|
||||||
// "device": {
|
|
||||||
// "connections": [
|
|
||||||
// [
|
|
||||||
// "cbus_group_address",
|
|
||||||
// "0"
|
|
||||||
// ]
|
|
||||||
// ],
|
|
||||||
// "identifiers": [
|
|
||||||
// "cbus_bin_sensor_0"
|
|
||||||
// ],
|
|
||||||
// "manufacturer": "Clipsal",
|
|
||||||
// "model": "C-Bus Lighting Application",
|
|
||||||
// "name": "C-Bus Light 000",
|
|
||||||
// "sw_version": "cmqttd https://github.com/micolous/cbus",
|
|
||||||
// "via_device": "cmqttd"
|
|
||||||
// },
|
|
||||||
// "name": "C-Bus Light 000 (as binary sensor)",
|
|
||||||
// "stat_t": "homeassistant/binary_sensor/cbus_0/state",
|
|
||||||
// "unique_id": "cbus_bin_sensor_0"
|
|
||||||
// }
|
|
||||||
|
|
||||||
type BinarySensor struct {
|
|
||||||
Availability *Availability `json:"availability,omitempty" required:"false"`
|
|
||||||
AvailabilityMode string `json:"availability_mode,omitempty" required:"false"`
|
|
||||||
AvailabilityTemplate string `json:"availability_template,omitempty" required:"false"`
|
|
||||||
AvailabilityTopic string `json:"availability_topic,omitempty" required:"false"`
|
|
||||||
Device Device `json:"device,omitempty" required:"false"`
|
|
||||||
DeviceClass string `json:"device_class,omitempty" required:"false"`
|
|
||||||
EnabledByDefault bool `json:"enabled_by_default,omitempty" required:"false"`
|
|
||||||
Encoding string `json:"encoding,omitempty" required:"false"`
|
|
||||||
EntityCategory string `json:"entity_category,omitempty" required:"false"`
|
|
||||||
ExpireAfter int `json:"expire_after,omitempty" required:"false"`
|
|
||||||
ForceUpdate bool `json:"force_update,omitempty" required:"false"`
|
|
||||||
Icon string `json:"icon,omitempty" required:"false"`
|
|
||||||
JsonAttributesTemplate string `json:"json_attributes_template,omitempty" required:"false"`
|
|
||||||
JsonAttributesTopic string `json:"json_attributes_topic,omitempty" required:"false"`
|
|
||||||
LastResetValueTemplate string `json:"last_reset_value_template,omitempty" required:"false"`
|
|
||||||
Name string `json:"name,omitempty" required:"false"`
|
|
||||||
ObjectId string `json:"object_id,omitempty" required:"false"`
|
|
||||||
PayloadAvailable string `json:"payload_available,omitempty" required:"false"`
|
|
||||||
PayloadNotAvailable string `json:"payload_not_available,omitempty" required:"false"`
|
|
||||||
Qos int `json:"qos,omitempty" required:"false"`
|
|
||||||
StateClass string `json:"state_class,omitempty" required:"false"`
|
|
||||||
StateTopic string `json:"state_topic" required:"true"`
|
|
||||||
UniqueId string `json:"unique_id,omitempty" required:"false"`
|
|
||||||
UnitOfMeasurement string `json:"unit_of_measurement,omitempty" required:"false"`
|
|
||||||
ValueTemplate string `json:"value_template,omitempty" required:"false"`
|
|
||||||
|
|
||||||
OffDelay int `json:"off_delay,omitempty" required:"false"`
|
|
||||||
PayloadOff string `json:"pl_off,omitempty" required:"false"`
|
|
||||||
PayloadOn string `json:"pl_on,omitempty" required:"false"`
|
|
||||||
}
|
|
||||||
type Availability struct {
|
|
||||||
PayloadAvailable string `json:"payload_available,omitempty" required:"false"`
|
|
||||||
PayloadNotAvailable string `json:"payload_not_available,omitempty" required:"false"`
|
|
||||||
Topic string `json:"topic,omitempty" required:"true"`
|
|
||||||
ValueTemplate string `json:"value_template,omitempty" required:"false"`
|
|
||||||
}
|
|
||||||
type SensorState string
|
|
||||||
|
|
||||||
func (c *BinarySensor) Json() string {
|
|
||||||
j, _ := json.Marshal(*c)
|
|
||||||
return string(j)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type Sensor struct {
|
|
||||||
Availability *Availability `json:"availability,omitempty" required:"false"`
|
|
||||||
AvailabilityMode string `json:"availability_mode,omitempty" required:"false"`
|
|
||||||
AvailabilityTemplate string `json:"availability_template,omitempty" required:"false"`
|
|
||||||
AvailabilityTopic string `json:"availability_topic,omitempty" required:"false"`
|
|
||||||
Device Device `json:"device,omitempty" required:"false"`
|
|
||||||
DeviceClass string `json:"device_class,omitempty" required:"false"`
|
|
||||||
EnabledByDefault bool `json:"enabled_by_default,omitempty" required:"false"`
|
|
||||||
Encoding string `json:"encoding,omitempty" required:"false"`
|
|
||||||
EntityCategory string `json:"entity_category,omitempty" required:"false"`
|
|
||||||
ExpireAfter int `json:"expire_after,omitempty" required:"false"`
|
|
||||||
ForceUpdate bool `json:"force_update,omitempty" required:"false"`
|
|
||||||
Icon string `json:"icon,omitempty" required:"false"`
|
|
||||||
JsonAttributesTemplate string `json:"json_attributes_template,omitempty" required:"false"`
|
|
||||||
JsonAttributesTopic string `json:"json_attributes_topic,omitempty" required:"false"`
|
|
||||||
LastResetValueTemplate string `json:"last_reset_value_template,omitempty" required:"false"`
|
|
||||||
Name string `json:"name,omitempty" required:"false"`
|
|
||||||
ObjectId string `json:"object_id,omitempty" required:"false"`
|
|
||||||
PayloadAvailable string `json:"payload_available,omitempty" required:"false"`
|
|
||||||
PayloadNotAvailable string `json:"payload_not_available,omitempty" required:"false"`
|
|
||||||
Qos int `json:"qos,omitempty" required:"false"`
|
|
||||||
StateClass string `json:"state_class,omitempty" required:"false"`
|
|
||||||
StateTopic string `json:"state_topic" required:"true"`
|
|
||||||
UniqueId string `json:"unique_id,omitempty" required:"false"`
|
|
||||||
UnitOfMeasurement string `json:"unit_of_measurement,omitempty" required:"false"`
|
|
||||||
ValueTemplate string `json:"value_template,omitempty" required:"false"`
|
|
||||||
LastReset string `json:"last_reset,omitempty" required:"false"`
|
|
||||||
|
|
||||||
// StateFunc func() string `json:"-"`
|
|
||||||
//
|
|
||||||
// UpdateInterval float64 `json:"-"`
|
|
||||||
// ForceUpdateMQTT bool `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Sensor) Json() string {
|
|
||||||
j, _ := json.Marshal(*c)
|
|
||||||
return string(j)
|
|
||||||
}
|
|
371
mmMqtt/struct.go
371
mmMqtt/struct.go
@ -1,371 +0,0 @@
|
|||||||
package mmMqtt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"GoSungrow/Only"
|
|
||||||
"GoSungrow/iSolarCloud/api"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
type Mqtt struct {
|
|
||||||
ClientId string `json:"client_id"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
Port string `json:"port"`
|
|
||||||
|
|
||||||
url *url.URL
|
|
||||||
client mqtt.Client
|
|
||||||
pubClient mqtt.Client
|
|
||||||
clientOptions *mqtt.ClientOptions
|
|
||||||
LastRefresh time.Time `json:"-"`
|
|
||||||
PsId int64 `json:"-"`
|
|
||||||
|
|
||||||
firstRun bool
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(req Mqtt) *Mqtt {
|
|
||||||
var ret Mqtt
|
|
||||||
|
|
||||||
for range Only.Once {
|
|
||||||
ret.err = ret.setUrl(req)
|
|
||||||
if ret.err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ret.firstRun = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) IsFirstRun() bool {
|
|
||||||
return m.firstRun
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) IsNotFirstRun() bool {
|
|
||||||
return !m.firstRun
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) UnsetFirstRun() {
|
|
||||||
m.firstRun = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) GetError() error {
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) IsError() bool {
|
|
||||||
if m.err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) IsNewDay() bool {
|
|
||||||
var yes bool
|
|
||||||
for range Only.Once {
|
|
||||||
last := m.LastRefresh.Format("20060102")
|
|
||||||
now := time.Now().Format("20060102")
|
|
||||||
|
|
||||||
if last != now {
|
|
||||||
yes = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return yes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) setUrl(req Mqtt) error {
|
|
||||||
|
|
||||||
for range Only.Once {
|
|
||||||
// if req.Username == "" {
|
|
||||||
// m.err = errors.New("username empty")
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
m.Username = req.Username
|
|
||||||
|
|
||||||
// if req.Password == "" {
|
|
||||||
// m.err = errors.New("password empty")
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
m.Password = req.Password
|
|
||||||
|
|
||||||
if req.Host == "" {
|
|
||||||
m.err = errors.New("HASSIO mqtt host not defined")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
m.Host = req.Host
|
|
||||||
|
|
||||||
if req.Port == "" {
|
|
||||||
req.Port = "1883"
|
|
||||||
}
|
|
||||||
m.Port = req.Port
|
|
||||||
|
|
||||||
u := fmt.Sprintf("tcp://%s:%s@%s:%s",
|
|
||||||
m.Username,
|
|
||||||
m.Password,
|
|
||||||
m.Host,
|
|
||||||
m.Port,
|
|
||||||
)
|
|
||||||
m.url, m.err = url.Parse(u)
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) SetAuth(username string, password string) error {
|
|
||||||
|
|
||||||
for range Only.Once {
|
|
||||||
if username == "" {
|
|
||||||
m.err = errors.New("username empty")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
m.Username = username
|
|
||||||
|
|
||||||
if password == "" {
|
|
||||||
m.err = errors.New("password empty")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
m.Password = password
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) Connect() error {
|
|
||||||
for range Only.Once {
|
|
||||||
m.err = m.createClientOptions()
|
|
||||||
if m.err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
m.client = mqtt.NewClient(m.clientOptions)
|
|
||||||
token := m.client.Connect()
|
|
||||||
for !token.WaitTimeout(3 * time.Second) {
|
|
||||||
}
|
|
||||||
if m.err = token.Error(); m.err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
device := Config {
|
|
||||||
Entry: ServiceBaseTopic,
|
|
||||||
Name: ServiceBaseName,
|
|
||||||
UniqueId: ServiceBaseUniqueId,
|
|
||||||
StateTopic: "~/state",
|
|
||||||
DeviceConfig: DeviceConfig {
|
|
||||||
Identifiers: []string{"GoSunGrow", "SunGrow"},
|
|
||||||
SwVersion: "GoSunGrow https://github.com/MickMake/GoSungrow",
|
|
||||||
Name: ServiceBaseName,
|
|
||||||
Manufacturer: "MickMake",
|
|
||||||
Model: "SunGrow",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
m.err = m.Publish(ServiceBaseTopic + "/config", 0, true, device.Json())
|
|
||||||
if m.err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
m.err = m.Publish(ServiceBaseTopic + "/state", 0, true, "ON")
|
|
||||||
if m.err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
const ServiceBaseName = "GoSunGrow"
|
|
||||||
const ServiceBaseUniqueId = ServiceBaseName + "_Service"
|
|
||||||
const ServiceBaseTopic = "homeassistant/sensor/" + ServiceBaseName
|
|
||||||
const SensorBaseTopic = "homeassistant/sensor/" + ServiceBaseName
|
|
||||||
|
|
||||||
func (m *Mqtt) createClientOptions() error {
|
|
||||||
for range Only.Once {
|
|
||||||
m.clientOptions = mqtt.NewClientOptions()
|
|
||||||
m.clientOptions.AddBroker(fmt.Sprintf("tcp://%s", m.url.Host))
|
|
||||||
m.clientOptions.SetUsername(m.url.User.Username())
|
|
||||||
password, _ := m.url.User.Password()
|
|
||||||
m.clientOptions.SetPassword(password)
|
|
||||||
m.clientOptions.SetClientID(m.ClientId)
|
|
||||||
|
|
||||||
m.clientOptions.WillTopic = ServiceBaseTopic + "/state"
|
|
||||||
m.clientOptions.WillPayload = []byte("OFF")
|
|
||||||
m.clientOptions.WillQos = 0
|
|
||||||
m.clientOptions.WillRetained = true
|
|
||||||
m.clientOptions.WillEnabled = true
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) Subscribe(topic string) error {
|
|
||||||
for range Only.Once {
|
|
||||||
m.client.Subscribe(topic, 0, func(client mqtt.Client, msg mqtt.Message) {
|
|
||||||
fmt.Printf("* [%s] %s\n", msg.Topic(), string(msg.Payload()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) Publish(topic string, qos byte, retained bool, payload interface{}) error {
|
|
||||||
for range Only.Once {
|
|
||||||
m.client.Publish(topic, qos, retained, payload)
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) SensorPublish(subtopic string, payload interface{}) error {
|
|
||||||
for range Only.Once {
|
|
||||||
m.client.Publish(SensorBaseTopic + "/" + subtopic, 0, true, payload)
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (m *Mqtt) SensorPublishConfig(id string, name string, units string, address int) error {
|
|
||||||
func (m *Mqtt) SensorPublishConfig(point api.DataEntry) error {
|
|
||||||
for range Only.Once {
|
|
||||||
a := strconv.Itoa(point.Index)
|
|
||||||
id := strings.ReplaceAll("sungrow_" + point.PointId, ".", "-")
|
|
||||||
|
|
||||||
class := ""
|
|
||||||
switch point.Unit {
|
|
||||||
case "MW":
|
|
||||||
fallthrough
|
|
||||||
case "kW":
|
|
||||||
fallthrough
|
|
||||||
case "W":
|
|
||||||
class = "power"
|
|
||||||
|
|
||||||
case "MWh":
|
|
||||||
fallthrough
|
|
||||||
case "kWh":
|
|
||||||
fallthrough
|
|
||||||
case "Wh":
|
|
||||||
class = "energy"
|
|
||||||
|
|
||||||
case "kvar":
|
|
||||||
class = "reactive_power"
|
|
||||||
|
|
||||||
case "Hz":
|
|
||||||
class = "frequency"
|
|
||||||
|
|
||||||
case "V":
|
|
||||||
class = "voltage"
|
|
||||||
|
|
||||||
case "A":
|
|
||||||
class = "current"
|
|
||||||
|
|
||||||
case "℃":
|
|
||||||
class = "temperature"
|
|
||||||
// point.Unit = "C"
|
|
||||||
|
|
||||||
case "C":
|
|
||||||
class = "temperature"
|
|
||||||
point.Unit = "℃"
|
|
||||||
|
|
||||||
case "%":
|
|
||||||
class = "battery"
|
|
||||||
}
|
|
||||||
|
|
||||||
LastReset := m.GetLastReset(point.PointId)
|
|
||||||
LastResetValueTemplate := ""
|
|
||||||
if LastReset != "" {
|
|
||||||
LastResetValueTemplate = "{{ value_json.last_reset | as_datetime() }}"
|
|
||||||
// LastResetValueTemplate = "{{ value_json.last_reset | int | timestamp_local | as_datetime }}"
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := Sensor {
|
|
||||||
Device: Device {
|
|
||||||
Connections: [][]string{{"sungrow_address", a}},
|
|
||||||
Identifiers: []string{id, "sungrow_address_" + a},
|
|
||||||
Manufacturer: "MickMake",
|
|
||||||
Model: "SunGrow inverter",
|
|
||||||
Name: point.PointName,
|
|
||||||
SwVersion: "GoSunGrow https://github.com/MickMake/GoSungrow",
|
|
||||||
ViaDevice: "gosungrow",
|
|
||||||
},
|
|
||||||
Name: "SunGrow " + point.PointName,
|
|
||||||
StateClass: "measurement",
|
|
||||||
StateTopic: SensorBaseTopic + "/" + id + "/state",
|
|
||||||
UniqueId: id,
|
|
||||||
UnitOfMeasurement: point.Unit,
|
|
||||||
DeviceClass: class,
|
|
||||||
Qos: 0,
|
|
||||||
ForceUpdate: true,
|
|
||||||
ExpireAfter: 0,
|
|
||||||
Encoding: "utf-8",
|
|
||||||
EnabledByDefault: true,
|
|
||||||
LastResetValueTemplate: LastResetValueTemplate,
|
|
||||||
LastReset: LastReset,
|
|
||||||
ValueTemplate: "{{ value_json.value | float }}",
|
|
||||||
// LastReset: time.Now().Format("2006-01-02T00:00:00+00:00"),
|
|
||||||
// LastResetValueTemplate: "{{entity_id}}",
|
|
||||||
// LastResetValueTemplate: "{{ (as_datetime((value_json.last_reset | int | timestamp_utc)|string+'Z')).isoformat() }}",
|
|
||||||
}
|
|
||||||
|
|
||||||
m.client.Publish(SensorBaseTopic + "/" + id + "/config", 0, true, payload.Json())
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (m *Mqtt) SensorPublishValue(id string, value string) error {
|
|
||||||
func (m *Mqtt) SensorPublishValue(point api.DataEntry) error {
|
|
||||||
for range Only.Once {
|
|
||||||
id := strings.ReplaceAll("sungrow_" + point.PointId, ".", "-")
|
|
||||||
payload := MqttState {
|
|
||||||
LastReset: m.GetLastReset(point.PointId),
|
|
||||||
Value: point.Value,
|
|
||||||
}
|
|
||||||
m.client.Publish(SensorBaseTopic + "/" + id + "/state", 0, true, payload.Json())
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) GetLastReset(pointType string) string {
|
|
||||||
var ret string
|
|
||||||
|
|
||||||
for range Only.Once {
|
|
||||||
pt := api.GetDevicePoint(pointType)
|
|
||||||
if pt == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ret = pt.WhenReset()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mqtt) SensorPublishState(id string, payload interface{}) error {
|
|
||||||
for range Only.Once {
|
|
||||||
id = strings.ReplaceAll("sungrow_" + id, ".", "-")
|
|
||||||
m.client.Publish(SensorBaseTopic + "/" + id + "/state", 0, true, payload)
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type MqttState struct {
|
|
||||||
LastReset string `json:"last_reset,omitempty"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mq *MqttState) Json() string {
|
|
||||||
var ret string
|
|
||||||
for range Only.Once {
|
|
||||||
j, err := json.Marshal(*mq)
|
|
||||||
if err != nil {
|
|
||||||
ret = fmt.Sprintf("{ \"error\": \"%s\"", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ret = string(j)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
package mmMqtt
|
|
||||||
|
|
||||||
|
|
||||||
type Switch struct {
|
|
||||||
AvailabilityTopic string `json:"avty_t,omitempty"`
|
|
||||||
CommandTopic string `json:"cmd_t"`
|
|
||||||
Device Device `json:"dev,omitempty"`
|
|
||||||
Icon string `json:"ic,omitempty"`
|
|
||||||
JSONAttributesTemplate string `json:"json_attr_tpl,omitempty"`
|
|
||||||
JSONAttributesTopic string `json:"json_attr_t,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Optimistic bool `json:"opt,omitempty"`
|
|
||||||
PayloadAvailable string `json:"pl_avail,omitempty"`
|
|
||||||
PayloadNotAvailable string `json:"pl_not_avail,omitempty"`
|
|
||||||
PayloadOff string `json:"pl_off,omitempty"`
|
|
||||||
PayloadOn string `json:"pl_on,omitempty"`
|
|
||||||
QOS int `json:"qos,omitempty"`
|
|
||||||
Retain bool `json:"ret,omitempty"`
|
|
||||||
StateOff string `json:"stat_off,omitempty"`
|
|
||||||
StateOn string `json:"stat_on,omitempty"`
|
|
||||||
StateTopic string `json:"stat_t,omitempty"`
|
|
||||||
UniqueID string `json:"uniq_id,omitempty"`
|
|
||||||
ValueTemplate string `json:"val_tpl,omitempty"`
|
|
||||||
|
|
||||||
// CommandFunc func(mqtt.Message, mqtt.Client) `json:"-"`
|
|
||||||
// StateFunc func() string `json:"-"`
|
|
||||||
//
|
|
||||||
// UpdateInterval float64 `json:"-"`
|
|
||||||
// ForceUpdateMQTT bool `json:"-"`
|
|
||||||
//
|
|
||||||
// messageHandler mqtt.MessageHandler
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user