mirror of
https://github.com/MickMake/GoSungrow.git
synced 2025-03-26 17:41:42 +01: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 name="ChangeListManager">
|
||||
<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$/HA/CHANGELOG.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/HA/Dockerfile" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/HA/GoSungrow" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/HA/build.yaml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/HA/config.yaml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/HA/src/GoSungrow" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/HA/src/run.sh" 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$/cmd/struct.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/struct.go" afterDir="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$/iSolarCloud/AppService/getPsList/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/getPsList/data.go" afterDir="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$/iSolarCloud/api/struct_points.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/struct_points.go" afterDir="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>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@ -79,7 +85,7 @@
|
||||
<configuration name="GoSungrow" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||
<module name="GoSungrow" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<parameters value="data get template 8092 20220301" />
|
||||
<parameters value="mqtt run" />
|
||||
<kind value="PACKAGE" />
|
||||
<package value="$PROJECT_DIR$" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
@ -87,6 +93,23 @@
|
||||
<output_directory value="$PROJECT_DIR$/bin" />
|
||||
<method v="2" />
|
||||
</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 name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@ -165,12 +188,12 @@
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||
<line>207</line>
|
||||
<line>232</line>
|
||||
<option name="timeStamp" value="437" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||
<line>206</line>
|
||||
<line>231</line>
|
||||
<option name="timeStamp" value="446" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
@ -190,27 +213,12 @@
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/api/struct_points.go</url>
|
||||
<line>288</line>
|
||||
<line>289</line>
|
||||
<option name="timeStamp" value="523" />
|
||||
</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">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>492</line>
|
||||
<line>518</line>
|
||||
<option name="timeStamp" value="570" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
@ -223,16 +231,6 @@
|
||||
<line>136</line>
|
||||
<option name="timeStamp" value="581" />
|
||||
</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">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>79</line>
|
||||
@ -243,6 +241,46 @@
|
||||
<line>75</line>
|
||||
<option name="timeStamp" value="593" />
|
||||
</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>
|
||||
</breakpoint-manager>
|
||||
<watches-manager>
|
||||
|
209
cmd/cmd_mqtt.go
209
cmd/cmd_mqtt.go
@ -2,11 +2,12 @@ package cmd
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/mmMqtt"
|
||||
"GoSungrow/mmHa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-co-op/gocron"
|
||||
"github.com/spf13/cobra"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@ -70,8 +71,33 @@ func (ca *CommandArgs) MqttArgs(cmd *cobra.Command, args []string) error {
|
||||
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")
|
||||
Cmd.Mqtt = mmMqtt.New(mmMqtt.Mqtt {
|
||||
Cmd.Mqtt = mmHa.New(mmHa.Mqtt {
|
||||
ClientId: "GoSunGrow",
|
||||
Username: Cmd.MqttUsername,
|
||||
Password: Cmd.MqttPassword,
|
||||
@ -83,24 +109,23 @@ func (ca *CommandArgs) MqttArgs(cmd *cobra.Command, args []string) error {
|
||||
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()
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
LogPrintDate("Connecting to SunGrow...\n")
|
||||
Cmd.Error = Cmd.SunGrowArgs(cmd, args)
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
// 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
|
||||
@ -231,21 +256,64 @@ func MqttCron() error {
|
||||
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,
|
||||
ep := Cmd.SunGrow.QueryDevice(Cmd.Mqtt.PsId)
|
||||
if ep.IsError() {
|
||||
Cmd.Error = ep.GetError()
|
||||
break
|
||||
}
|
||||
|
||||
data := ep.GetData()
|
||||
|
||||
if Cmd.Mqtt.IsNewDay() {
|
||||
if newDay {
|
||||
LogPrintDate("New day: Configuring %d entries in HASSIO.\n", len(data.Entries))
|
||||
for _, r := range data.Entries {
|
||||
fmt.Printf(".")
|
||||
// Cmd.Error = Cmd.Mqtt.SensorPublishConfig(r.PointId, r.PointName, r.Unit, i)
|
||||
Cmd.Error = Cmd.Mqtt.SensorPublishConfig(r)
|
||||
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 {
|
||||
break
|
||||
}
|
||||
|
||||
Cmd.Error = Cmd.Mqtt.SensorPublishConfig(re)
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
@ -255,20 +323,111 @@ func MqttCron() error {
|
||||
|
||||
LogPrintDate("Updating %d entries to HASSIO.\n", len(data.Entries))
|
||||
for _, r := range data.Entries {
|
||||
fmt.Printf(".")
|
||||
// Cmd.Error = Cmd.Mqtt.SensorPublishState(r.PointId, r.Value)
|
||||
Cmd.Error = Cmd.Mqtt.SensorPublishValue(r)
|
||||
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()
|
||||
}
|
||||
|
||||
Cmd.Mqtt.LastRefresh = time.Now()
|
||||
if Cmd.Error != nil {
|
||||
LogPrintDate("Error: %s\n", Cmd.Error)
|
||||
}
|
||||
return Cmd.Error
|
||||
}
|
||||
|
||||
if Cmd.Error != nil {
|
||||
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 {
|
||||
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 {
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"GoSungrow/iSolarCloud/AppService/login"
|
||||
"GoSungrow/lsgo"
|
||||
"GoSungrow/mmGit"
|
||||
"GoSungrow/mmMqtt"
|
||||
"GoSungrow/mmHa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
@ -21,7 +21,7 @@ var DefaultAreas = []string{"all"}
|
||||
type CommandArgs struct {
|
||||
SunGrow *iSolarCloud.SunGrow
|
||||
Git *mmGit.Git
|
||||
Mqtt *mmMqtt.Mqtt
|
||||
Mqtt *mmHa.Mqtt
|
||||
|
||||
ConfigDir string
|
||||
CacheDir string
|
||||
|
@ -192,7 +192,7 @@ func (e *EndPoint) GetDataTable() output.Table {
|
||||
keys := api.GetStructKeys(e.Response.ResultData)
|
||||
for _, n := range keys.Sort() {
|
||||
p := api.GetPoint(e.Response.ResultData.PsPsKey, n)
|
||||
if p != nil {
|
||||
if p.Valid {
|
||||
_ = table.AddRow(
|
||||
now,
|
||||
api.NameDevicePoint(e.Response.ResultData.PsPsKey, n),
|
||||
@ -222,7 +222,7 @@ func (e *EndPoint) GetDataTable() output.Table {
|
||||
keys = api.GetStructKeys(sid)
|
||||
for _, n := range keys.Sort() {
|
||||
p := api.GetPoint(sid.PsKey, n)
|
||||
if p != nil {
|
||||
if p.Valid {
|
||||
_ = table.AddRow(
|
||||
now,
|
||||
api.NameDevicePoint(sid.PsKey, n),
|
||||
@ -304,6 +304,45 @@ func (e *EndPoint) GetPsKeys() []string {
|
||||
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
|
||||
// Co2ReduceTotal
|
||||
// CoalReduceTotal
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"GoSungrow/iSolarCloud/api/apiReflect"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -200,44 +201,239 @@ func (e *ResultData) GetPsId() int64 {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (e *EndPoint) GetPsId() int64 {
|
||||
return e.Response.ResultData.GetPsId()
|
||||
}
|
||||
|
||||
func (e *ResultData) GetData() [][]string {
|
||||
var ret [][]string
|
||||
func (e *ResultData) GetPsName() 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})
|
||||
if p.PsID != 0 {
|
||||
ret = p.PsName
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
var table output.Table
|
||||
for range Only.Once {
|
||||
|
@ -298,7 +298,9 @@ func (e *EndPoint) GetData() api.Data {
|
||||
|
||||
var TotalDcPower float64
|
||||
|
||||
index := 0
|
||||
var TotalLoadActivePower float64
|
||||
|
||||
// index := 0
|
||||
for _, d := range e.Response.ResultData.PageList {
|
||||
for _, p := range d.PointData {
|
||||
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 {
|
||||
Date: api.NewDateTime(p.TimeStamp),
|
||||
PointId: api.NameDevicePointInt(d.PsKey, p.PointID),
|
||||
@ -330,12 +342,10 @@ func (e *EndPoint) GetData() api.Data {
|
||||
PointName: p.PointName,
|
||||
Value: p.Value,
|
||||
Unit: p.Unit,
|
||||
ValueType: api.GetPointInt(d.PsKey, p.PointID),
|
||||
Index: index,
|
||||
ValueType: vt,
|
||||
Index: len(ret.Entries),
|
||||
})
|
||||
|
||||
index++
|
||||
|
||||
// Handle virtual results.
|
||||
switch strings.ReplaceAll(p.PointName, " ", "") {
|
||||
case "BatteryChargingPower":
|
||||
@ -346,6 +356,11 @@ func (e *EndPoint) GetData() api.Data {
|
||||
TotalExportActivePower, _ = strconv.ParseFloat(p.Value, 64)
|
||||
case "PurchasedPower":
|
||||
PurchasedPower, _ = strconv.ParseFloat(p.Value, 64)
|
||||
case "TotalDCPower":
|
||||
TotalDcPower, _ = strconv.ParseFloat(p.Value, 64)
|
||||
case "TotalLoadActivePower":
|
||||
TotalLoadActivePower, _ = strconv.ParseFloat(p.Value, 64)
|
||||
|
||||
case "DailyBatteryChargingEnergyFromPv":
|
||||
DailyBatteryChargingEnergyFromPv, _ = strconv.ParseFloat(p.Value, 64)
|
||||
case "DailyBatteryDischargingEnergy":
|
||||
@ -354,8 +369,6 @@ func (e *EndPoint) GetData() api.Data {
|
||||
DailyFeedInEnergyPv, _ = strconv.ParseFloat(p.Value, 64)
|
||||
case "DailyPurchasedEnergy":
|
||||
DailyPurchasedEnergy, _ = strconv.ParseFloat(p.Value, 64)
|
||||
case "TotalDCPower":
|
||||
TotalDcPower, _ = strconv.ParseFloat(p.Value, 64)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -366,122 +379,313 @@ func (e *EndPoint) GetData() api.Data {
|
||||
|
||||
// Add virtual entries.
|
||||
ts := ret.Entries[0].Date
|
||||
var value string
|
||||
var value float64
|
||||
|
||||
if BatteryChargingPower > 0 {
|
||||
value = api.Float64ToString(0 - BatteryChargingPower)
|
||||
} else {
|
||||
value = api.Float64ToString(BatteryDischargingPower)
|
||||
/*
|
||||
PVPower - TotalDcPower
|
||||
PVPowerToBattery - BatteryChargingPower
|
||||
PVPowerToLoad - TotalDcPower - BatteryChargingPower - TotalExportActivePower
|
||||
PVPowerToGrid - TotalExportActivePower
|
||||
|
||||
LoadPower - TotalLoadActivePower
|
||||
BatteryToLoad - BatteryDischargingPower
|
||||
BatteryToGrid - ?
|
||||
|
||||
GridPower - TotalDcPower
|
||||
GridToLoad - PurchasedPower
|
||||
GridToBattery - ?
|
||||
*/
|
||||
|
||||
|
||||
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 {
|
||||
value = 0 - DailyBatteryChargingEnergyFromPv
|
||||
} else {
|
||||
value = DailyBatteryDischargingEnergy
|
||||
}
|
||||
ret.Entries = append(ret.Entries, api.DataEntry{
|
||||
Date: ts,
|
||||
PointId: "virtual.battery_energy",
|
||||
PointGroupName: "Virtual",
|
||||
PointName: "Battery Energy",
|
||||
Value: api.Float64ToString(value),
|
||||
Unit: "kWh",
|
||||
ValueType: &api.Point{
|
||||
PsKey: "virtual",
|
||||
Id: "battery_energy",
|
||||
Description: "Battery Energy",
|
||||
Unit: "kWh",
|
||||
Type: "PointTypeInstant",
|
||||
},
|
||||
Index: len(ret.Entries),
|
||||
})
|
||||
}
|
||||
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 {
|
||||
value = api.Float64ToString(0 - TotalExportActivePower)
|
||||
} else {
|
||||
value = api.Float64ToString(PurchasedPower)
|
||||
{
|
||||
if DailyFeedInEnergyPv > 0 {
|
||||
value = 0 - DailyFeedInEnergyPv
|
||||
} else {
|
||||
value = DailyPurchasedEnergy
|
||||
}
|
||||
ret.Entries = append(ret.Entries, api.DataEntry{
|
||||
Date: ts,
|
||||
PointId: "virtual.grid_energy",
|
||||
PointGroupName: "Virtual",
|
||||
PointName: "Grid Energy",
|
||||
Value: api.Float64ToString(value),
|
||||
Unit: "kWh",
|
||||
ValueType: &api.Point{
|
||||
PsKey: "virtual",
|
||||
Id: "grid_energy",
|
||||
Description: "Grid Energy",
|
||||
Unit: "kWh",
|
||||
Type: "PointTypeInstant",
|
||||
},
|
||||
Index: len(ret.Entries),
|
||||
})
|
||||
}
|
||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
||||
Date: ts,
|
||||
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++
|
||||
|
||||
|
||||
if DailyBatteryChargingEnergyFromPv > 0 {
|
||||
value = api.Float64ToString(0 - DailyBatteryChargingEnergyFromPv)
|
||||
} else {
|
||||
value = api.Float64ToString(DailyBatteryDischargingEnergy)
|
||||
}
|
||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
||||
Date: ts,
|
||||
PointId: "virtual.battery_energy",
|
||||
PointGroupName: "Virtual",
|
||||
PointName: "Battery Energy",
|
||||
Value: value,
|
||||
Unit: "kWh",
|
||||
ValueType: &api.Point {
|
||||
PsKey: "virtual",
|
||||
Id: "battery_energy",
|
||||
Description: "Battery Energy",
|
||||
Unit: "kWh",
|
||||
Type: "PointTypeInstant",
|
||||
},
|
||||
Index: index,
|
||||
})
|
||||
index++
|
||||
|
||||
if DailyFeedInEnergyPv > 0 {
|
||||
value = api.Float64ToString(0 - DailyFeedInEnergyPv)
|
||||
} else {
|
||||
value = api.Float64ToString(DailyPurchasedEnergy)
|
||||
}
|
||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
||||
Date: ts,
|
||||
PointId: "virtual.grid_energy",
|
||||
PointGroupName: "Virtual",
|
||||
PointName: "Grid Energy",
|
||||
Value: value,
|
||||
Unit: "kWh",
|
||||
ValueType: &api.Point {
|
||||
PsKey: "virtual",
|
||||
Id: "grid_energy",
|
||||
Description: "Grid Energy",
|
||||
Unit: "kWh",
|
||||
Type: "PointTypeInstant",
|
||||
},
|
||||
Index: index,
|
||||
})
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
Unit string
|
||||
Type string
|
||||
Valid bool
|
||||
}
|
||||
type PointsMap map[string]Point
|
||||
|
||||
@ -292,15 +293,24 @@ func (p Point) String() string {
|
||||
func (pm PointsMap) Get(device string, point string) *Point {
|
||||
dp := device + ".p" + strings.TrimPrefix(point, "p")
|
||||
if p, ok := pm[dp]; ok {
|
||||
p.Valid = true
|
||||
return &p
|
||||
}
|
||||
|
||||
dp = "p" + strings.TrimPrefix(point, "p")
|
||||
if p, ok := pm[dp]; ok {
|
||||
p.Valid = true
|
||||
return &p
|
||||
}
|
||||
|
||||
return nil
|
||||
return &Point {
|
||||
PsKey: device,
|
||||
Id: dp,
|
||||
Description: "",
|
||||
Unit: "",
|
||||
Type: "",
|
||||
Valid: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (pm PointsMap) GetDevicePoint(devicePoint string) *Point {
|
||||
@ -372,3 +382,18 @@ type DataEntry struct {
|
||||
ValueType *Point `json:"value_type"`
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
for range Only.Once {
|
||||
for _, dt := range getPowerDevicePointNames.DeviceTypes {
|
||||
@ -540,6 +566,76 @@ func (sg *SunGrow) GetPsId() (int64, 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) {
|
||||
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"
|
||||
|
||||
|
||||
// {
|
||||
// "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 {
|
||||
Entry string `json:"~,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"`
|
||||
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"
|
@ -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 {
|
||||
@ -74,6 +131,11 @@ type Light struct {
|
||||
// messageHandler mqtt.MessageHandler
|
||||
}
|
||||
|
||||
func (c *Light) Json() string {
|
||||
j, _ := json.Marshal(*c)
|
||||
return string(j)
|
||||
}
|
||||
|
||||
|
||||
// {
|
||||
// "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