v1.4.1
137
.idea/workspace.xml
generated
@ -5,10 +5,36 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="76adadc9-ae71-42a6-82a1-66dbc8ecb14c" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/iSolarCloud/api/struct_points.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/iSolarCloud/points.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/mmMqtt/cron.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/cmd.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/cmd.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/cmd_config.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/cmd_config.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/cmd_cron.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/cmd_cron.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/cmd_data.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/cmd_data.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/cmd_data_sub.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/cmd_data_sub.go" afterDir="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/const.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/const.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/struct.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/struct.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/viper.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/viper.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/examples.txt" beforeDir="false" afterPath="$PROJECT_DIR$/examples.txt" 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/login/auth.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/login/auth.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/login/struct.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/login/struct.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/AppService/queryDeviceRealTimeDataByPsKeys/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceRealTimeDataByPsKeys/data.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/WebAppService/struct.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/WebAppService/struct.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/apiReflect/reflect.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/apiReflect/reflect.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/datetime.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/datetime.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/struct_response.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/struct_response.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/types.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/types.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/utils.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/utils.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/funcs.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/funcs.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/highlevel.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/highlevel.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/iSolarCloud/struct.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/struct.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/mmMqtt/sensors.go" beforeDir="false" afterPath="$PROJECT_DIR$/mmMqtt/sensors.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/mmMqtt/struct.go" beforeDir="false" afterPath="$PROJECT_DIR$/mmMqtt/struct.go" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@ -74,7 +100,7 @@
|
||||
<configuration name="GoSungrow" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||
<module name="GoSungrow" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<parameters value="mqtt" />
|
||||
<parameters value="data get realtime 1129147" />
|
||||
<kind value="PACKAGE" />
|
||||
<package value="$PROJECT_DIR$" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
@ -116,11 +142,6 @@
|
||||
<line>217</line>
|
||||
<option name="timeStamp" value="89" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/cmd/cmd_data.go</url>
|
||||
<line>201</line>
|
||||
<option name="timeStamp" value="95" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_csv.go</url>
|
||||
<line>165</line>
|
||||
@ -158,17 +179,17 @@
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceList/data.go</url>
|
||||
<line>199</line>
|
||||
<line>200</line>
|
||||
<option name="timeStamp" value="202" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/funcs.go</url>
|
||||
<line>133</line>
|
||||
<line>135</line>
|
||||
<option name="timeStamp" value="210" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/funcs.go</url>
|
||||
<line>121</line>
|
||||
<line>123</line>
|
||||
<option name="timeStamp" value="211" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
@ -198,14 +219,106 @@
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||
<line>109</line>
|
||||
<option name="timeStamp" value="393" />
|
||||
<line>239</line>
|
||||
<option name="timeStamp" value="437" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||
<line>238</line>
|
||||
<option name="timeStamp" value="446" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>375</line>
|
||||
<option name="timeStamp" value="476" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>391</line>
|
||||
<option name="timeStamp" value="477" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceRealTimeDataByPsKeys/data.go</url>
|
||||
<line>107</line>
|
||||
<option name="timeStamp" value="478" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceRealTimeDataByPsKeys/data.go</url>
|
||||
<line>142</line>
|
||||
<option name="timeStamp" value="479" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>412</line>
|
||||
<option name="timeStamp" value="480" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>422</line>
|
||||
<option name="timeStamp" value="481" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>405</line>
|
||||
<option name="timeStamp" value="483" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/getPsDetailWithPsType/data.go</url>
|
||||
<line>260</line>
|
||||
<option name="timeStamp" value="511" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>461</line>
|
||||
<option name="timeStamp" value="521" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/api/struct_points.go</url>
|
||||
<line>288</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>170</line>
|
||||
<option name="timeStamp" value="562" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||
<line>266</line>
|
||||
<option name="timeStamp" value="564" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/cmd/cmd_mqtt.go</url>
|
||||
<line>259</line>
|
||||
<option name="timeStamp" value="565" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceList/data.go</url>
|
||||
<line>290</line>
|
||||
<option name="timeStamp" value="566" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/highlevel.go</url>
|
||||
<line>417</line>
|
||||
<option name="timeStamp" value="567" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceRealTimeDataByPsKeys/struct.go</url>
|
||||
<line>123</line>
|
||||
<option name="timeStamp" value="568" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
<watches-manager>
|
||||
<configuration name="GoApplicationRunConfiguration">
|
||||
<watch expression="cmdDataSave" language="go" />
|
||||
<watch expression="Cmd" language="go" />
|
||||
<watch expression="payload.LastReset" language="go" />
|
||||
</configuration>
|
||||
</watches-manager>
|
||||
</component>
|
||||
|
@ -49,6 +49,15 @@ func AttachRootCmd(cmd *cobra.Command) *cobra.Command {
|
||||
rootViper.SetDefault(flagGoogleSheetUpdate, false)
|
||||
_ = rootCmd.PersistentFlags().MarkHidden(flagGoogleSheetUpdate)
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(&Cmd.MqttUsername, flagMqttUsername, "", "", fmt.Sprintf("HASSIO: mqtt username."))
|
||||
rootViper.SetDefault(flagMqttUsername, "")
|
||||
rootCmd.PersistentFlags().StringVarP(&Cmd.MqttPassword, flagMqttPassword, "", "", fmt.Sprintf("HASSIO: mqtt password."))
|
||||
rootViper.SetDefault(flagMqttPassword, "")
|
||||
rootCmd.PersistentFlags().StringVarP(&Cmd.MqttHost, flagMqttHost, "", "", fmt.Sprintf("HASSIO: mqtt host."))
|
||||
rootViper.SetDefault(flagMqttHost, "")
|
||||
rootCmd.PersistentFlags().StringVarP(&Cmd.MqttPort, flagMqttPort, "", "", fmt.Sprintf("HASSIO: mqtt port."))
|
||||
rootViper.SetDefault(flagMqttPort, "")
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(&Cmd.GitRepo, flagGitRepo, "", "", fmt.Sprintf("Git: Repo url for updates."))
|
||||
rootViper.SetDefault(flagGitRepo, "")
|
||||
rootCmd.PersistentFlags().StringVarP(&Cmd.GitRepoDir, flagGitRepoDir, "", "", fmt.Sprintf("Git: Local repo directory."))
|
||||
|
@ -67,10 +67,10 @@ func cmdConfigFunc(cmd *cobra.Command, args []string) {
|
||||
|
||||
func cmdConfigWriteFunc(_ *cobra.Command, args []string) {
|
||||
for range Only.Once {
|
||||
if len(args) == 1 {
|
||||
Cmd.ConfigFile = args[0]
|
||||
rootViper.SetConfigFile(Cmd.ConfigFile)
|
||||
}
|
||||
// if len(args) == 1 {
|
||||
// Cmd.ConfigFile = args[0]
|
||||
// rootViper.SetConfigFile(Cmd.ConfigFile)
|
||||
// }
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Using config file '%s'\n", rootViper.ConfigFileUsed())
|
||||
Cmd.Error = openConfig()
|
||||
|
@ -219,6 +219,16 @@ func LogPrint(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
|
||||
func LogPrintDate(format string, args ...interface{}) {
|
||||
fmt.Printf("%s ", TimeNow())
|
||||
fmt.Printf(format, args...)
|
||||
// fmt.Println()
|
||||
}
|
||||
|
||||
func TimeNow() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func ReExecute() error {
|
||||
for range Only.Once {
|
||||
LogPrint("Running scheduled command '%s'\n", strings.Join(os.Args, " "))
|
||||
|
@ -25,21 +25,6 @@ func AttachCmdData(cmd *cobra.Command) *cobra.Command {
|
||||
cmdData.Example = PrintExamples(cmdData, "get <endpoint>", "put <endpoint>")
|
||||
|
||||
|
||||
// // ********************************************************************************
|
||||
// var cmdDataList = &cobra.Command{
|
||||
// Use: "ls",
|
||||
// Aliases: []string{"list"},
|
||||
// Short: fmt.Sprintf("List iSolarCloud high-level data commands."),
|
||||
// Long: fmt.Sprintf("List iSolarCloud high-level data commands."),
|
||||
// DisableFlagParsing: false,
|
||||
// DisableFlagsInUseLine: false,
|
||||
// // PreRunE: Cmd.SunGrowArgs,
|
||||
// Run: cmdDataListFunc,
|
||||
// Args: cobra.RangeArgs(0, 1),
|
||||
// }
|
||||
// cmdData.AddCommand(cmdDataList)
|
||||
// cmdDataList.Example = PrintExamples(cmdDataList, "", "areas", "endpoints", "<area name>")
|
||||
|
||||
// ********************************************************************************
|
||||
var cmdDataLogin = &cobra.Command{
|
||||
Use: "login",
|
||||
@ -77,6 +62,9 @@ func AttachCmdData(cmd *cobra.Command) *cobra.Command {
|
||||
AttachCmdDataTemplatePoints(cmdDataGet)
|
||||
AttachCmdDataPoints(cmdDataGet)
|
||||
AttachCmdDataPointNames(cmdDataGet)
|
||||
AttachCmdDataMqtt(cmdDataGet)
|
||||
AttachCmdDataRealTime(cmdDataGet)
|
||||
AttachCmdDataPsDetails(cmdDataGet)
|
||||
|
||||
// ********************************************************************************
|
||||
var cmdDataRaw = &cobra.Command{
|
||||
@ -98,6 +86,9 @@ func AttachCmdData(cmd *cobra.Command) *cobra.Command {
|
||||
AttachCmdDataTemplate(cmdDataRaw)
|
||||
AttachCmdDataPoints(cmdDataRaw)
|
||||
AttachCmdDataPointNames(cmdDataRaw)
|
||||
AttachCmdDataMqtt(cmdDataRaw)
|
||||
AttachCmdDataRealTime(cmdDataRaw)
|
||||
AttachCmdDataPsDetails(cmdDataRaw)
|
||||
|
||||
// ********************************************************************************
|
||||
var cmdDataSave = &cobra.Command{
|
||||
@ -119,6 +110,9 @@ func AttachCmdData(cmd *cobra.Command) *cobra.Command {
|
||||
AttachCmdDataTemplate(cmdDataSave)
|
||||
AttachCmdDataPoints(cmdDataSave)
|
||||
AttachCmdDataPointNames(cmdDataSave)
|
||||
AttachCmdDataMqtt(cmdDataSave)
|
||||
AttachCmdDataRealTime(cmdDataSave)
|
||||
AttachCmdDataPsDetails(cmdDataSave)
|
||||
|
||||
// ********************************************************************************
|
||||
var cmdDataGraph = &cobra.Command{
|
||||
@ -139,6 +133,7 @@ func AttachCmdData(cmd *cobra.Command) *cobra.Command {
|
||||
AttachCmdDataStats(cmdDataGraph)
|
||||
AttachCmdDataTemplate(cmdDataGraph)
|
||||
AttachCmdDataPoints(cmdDataGraph)
|
||||
AttachCmdDataRealTime(cmdDataGraph)
|
||||
|
||||
// ********************************************************************************
|
||||
var cmdDataPut = &cobra.Command{
|
||||
@ -159,50 +154,6 @@ func AttachCmdData(cmd *cobra.Command) *cobra.Command {
|
||||
}
|
||||
|
||||
|
||||
// func cmdDataFunc(cmd *cobra.Command, _ []string) {
|
||||
// Cmd.Error = cmd.Help()
|
||||
// }
|
||||
//
|
||||
// func cmdDataListFunc(_ *cobra.Command, _ []string) {
|
||||
// Cmd.SunGrow.ListHighLevel()
|
||||
// }
|
||||
//
|
||||
// func cmdDataGetFunc(_ *cobra.Command, args []string) {
|
||||
// for range Only.Once {
|
||||
// Cmd.SunGrow.OutputType.SetHuman()
|
||||
//
|
||||
// args = fillArray(3, args)
|
||||
// Cmd.Error = Cmd.SunGrow.GetHighLevel(args[0], args[1:]...)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func cmdDataRawFunc(_ *cobra.Command, args []string) {
|
||||
// for range Only.Once {
|
||||
// Cmd.SunGrow.OutputType.SetRaw()
|
||||
//
|
||||
// args = fillArray(3, args)
|
||||
// Cmd.Error = Cmd.SunGrow.GetHighLevel(args[0], args[1:]...)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func cmdDataSaveFunc(_ *cobra.Command, args []string) {
|
||||
// for range Only.Once {
|
||||
// Cmd.SunGrow.OutputType.SetFile()
|
||||
//
|
||||
// args = fillArray(3, args)
|
||||
// Cmd.Error = Cmd.SunGrow.GetHighLevel(args[0], args[1:]...)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func cmdDataGraphFunc(_ *cobra.Command, args []string) {
|
||||
// for range Only.Once {
|
||||
// Cmd.SunGrow.OutputType.SetGraph()
|
||||
//
|
||||
// args = fillArray(4, args)
|
||||
// Cmd.Error = Cmd.SunGrow.GetHighLevel(args[0], args[1:]...)
|
||||
// }
|
||||
// }
|
||||
|
||||
func cmdDataPutFunc(_ *cobra.Command, args []string) {
|
||||
for range Only.Once {
|
||||
fmt.Println("Not yet implemented.")
|
||||
|
@ -116,3 +116,72 @@ func AttachCmdDataPointNames(cmd *cobra.Command) *cobra.Command {
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func AttachCmdDataMqtt(cmd *cobra.Command) *cobra.Command {
|
||||
// ********************************************************************************
|
||||
var c = &cobra.Command{
|
||||
Use: "mqtt-server",
|
||||
Aliases: []string{"mqtt"},
|
||||
Short: fmt.Sprintf("Get iSolarCloud MQTT service login details."),
|
||||
Long: fmt.Sprintf("Get iSolarCloud MQTT service login details."),
|
||||
DisableFlagParsing: false,
|
||||
DisableFlagsInUseLine: false,
|
||||
PreRunE: Cmd.SunGrowArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
_ = SwitchOutput(cmd)
|
||||
args = fillArray(1, args)
|
||||
return Cmd.SunGrow.GetIsolarcloudMqtt(args[0])
|
||||
},
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
}
|
||||
cmd.AddCommand(c)
|
||||
c.Example = PrintExamples(c, "")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func AttachCmdDataRealTime(cmd *cobra.Command) *cobra.Command {
|
||||
// ********************************************************************************
|
||||
var c = &cobra.Command{
|
||||
Use: "real-time",
|
||||
Aliases: []string{"realtime"},
|
||||
Short: fmt.Sprintf("Get iSolarCloud real-time data."),
|
||||
Long: fmt.Sprintf("Get iSolarCloud real-time data."),
|
||||
DisableFlagParsing: false,
|
||||
DisableFlagsInUseLine: false,
|
||||
PreRunE: Cmd.SunGrowArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
_ = SwitchOutput(cmd)
|
||||
args = fillArray(1, args)
|
||||
return Cmd.SunGrow.GetRealTimeData(args[0])
|
||||
},
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
}
|
||||
cmd.AddCommand(c)
|
||||
c.Example = PrintExamples(c, "")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func AttachCmdDataPsDetails(cmd *cobra.Command) *cobra.Command {
|
||||
// ********************************************************************************
|
||||
var c = &cobra.Command{
|
||||
Use: "psdetails",
|
||||
Aliases: []string{"ps-details"},
|
||||
Short: fmt.Sprintf("Get iSolarCloud ps details."),
|
||||
Long: fmt.Sprintf("Get iSolarCloud ps details."),
|
||||
DisableFlagParsing: false,
|
||||
DisableFlagsInUseLine: false,
|
||||
PreRunE: Cmd.SunGrowArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
_ = SwitchOutput(cmd)
|
||||
args = fillArray(1, args)
|
||||
return Cmd.SunGrow.GetPsDetails(args[0])
|
||||
},
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
}
|
||||
cmd.AddCommand(c)
|
||||
c.Example = PrintExamples(c, "")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
376
cmd/cmd_mqtt.go
@ -3,9 +3,11 @@ package cmd
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/mmMqtt"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-co-op/gocron"
|
||||
"github.com/spf13/cobra"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -15,28 +17,43 @@ func AttachCmdMqtt(cmd *cobra.Command) *cobra.Command {
|
||||
var cmdMqtt = &cobra.Command{
|
||||
Use: "mqtt",
|
||||
Aliases: []string{""},
|
||||
Short: fmt.Sprintf("All things MQTT related."),
|
||||
Long: fmt.Sprintf("All things MQTT related."),
|
||||
Short: fmt.Sprintf("Connect to a HASSIO broker."),
|
||||
Long: fmt.Sprintf("Connect to a HASSIO broker."),
|
||||
DisableFlagParsing: false,
|
||||
DisableFlagsInUseLine: false,
|
||||
PreRunE: Cmd.ProcessArgs,
|
||||
PreRunE: Cmd.MqttArgs,
|
||||
RunE: cmdMqttFunc,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
cmd.AddCommand(cmdMqtt)
|
||||
cmdMqtt.Example = PrintExamples(cmdMqtt, "sync", "sync all")
|
||||
cmdMqtt.Example = PrintExamples(cmdMqtt, "run", "sync")
|
||||
|
||||
|
||||
// ******************************************************************************** //
|
||||
var cmdMqttSync = &cobra.Command{
|
||||
Use: "update",
|
||||
var cmdMqttRun = &cobra.Command{
|
||||
Use: "run",
|
||||
Aliases: []string{""},
|
||||
Short: fmt.Sprintf("Sync to an MQTT broker."),
|
||||
Long: fmt.Sprintf("Sync to an MQTT broker."),
|
||||
Short: fmt.Sprintf("One-off sync to a HASSIO broker."),
|
||||
Long: fmt.Sprintf("One-off sync to a HASSIO broker."),
|
||||
DisableFlagParsing: false,
|
||||
DisableFlagsInUseLine: false,
|
||||
PreRunE: Cmd.ProcessArgs,
|
||||
Run: cmdMqttSyncFunc,
|
||||
PreRunE: Cmd.MqttArgs,
|
||||
RunE: cmdMqttRunFunc,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
}
|
||||
cmdMqtt.AddCommand(cmdMqttRun)
|
||||
cmdMqttRun.Example = PrintExamples(cmdMqttRun, "")
|
||||
|
||||
// ******************************************************************************** //
|
||||
var cmdMqttSync = &cobra.Command{
|
||||
Use: "sync",
|
||||
Aliases: []string{""},
|
||||
Short: fmt.Sprintf("Sync to a HASSIO MQTT broker."),
|
||||
Long: fmt.Sprintf("Sync to a HASSIO MQTT broker."),
|
||||
DisableFlagParsing: false,
|
||||
DisableFlagsInUseLine: false,
|
||||
PreRunE: Cmd.MqttArgs,
|
||||
RunE: cmdMqttSyncFunc,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
}
|
||||
cmdMqtt.AddCommand(cmdMqttSync)
|
||||
@ -46,30 +63,56 @@ func AttachCmdMqtt(cmd *cobra.Command) *cobra.Command {
|
||||
}
|
||||
|
||||
|
||||
func cmdMqttFunc(cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
func (ca *CommandArgs) MqttArgs(cmd *cobra.Command, args []string) error {
|
||||
for range Only.Once {
|
||||
fmt.Println("# Starting MQTT HASSIO Service...")
|
||||
ca.Error = ca.ProcessArgs(cmd, args)
|
||||
if ca.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
foo := mmMqtt.New(mmMqtt.Mqtt{
|
||||
ClientId: "SunGrow",
|
||||
Username: "mickmake",
|
||||
Password: "rvsrzdd0",
|
||||
Host: "10.0.5.21",
|
||||
Port: "11883",
|
||||
LogPrintDate("Connecting to MQTT HASSIO Service...\n")
|
||||
Cmd.Mqtt = mmMqtt.New(mmMqtt.Mqtt {
|
||||
ClientId: "GoSunGrow",
|
||||
Username: Cmd.MqttUsername,
|
||||
Password: Cmd.MqttPassword,
|
||||
Host: Cmd.MqttHost,
|
||||
Port: Cmd.MqttPort,
|
||||
})
|
||||
err = foo.GetError()
|
||||
if err != nil {
|
||||
Cmd.Error = Cmd.Mqtt.GetError()
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
err = foo.Connect()
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
return Cmd.Error
|
||||
}
|
||||
|
||||
|
||||
func cmdMqttFunc(cmd *cobra.Command, _ []string) error {
|
||||
return cmd.Help()
|
||||
}
|
||||
|
||||
func cmdMqttRunFunc(_ *cobra.Command, _ []string) error {
|
||||
for range Only.Once {
|
||||
// switch1 := mmMqtt.BinarySensor {
|
||||
// Device: mmMqtt.Device {
|
||||
// Connections: [][]string{{"sungrow_address", "0"}},
|
||||
@ -93,131 +136,202 @@ func cmdMqttFunc(cmd *cobra.Command, args []string) error {
|
||||
// break
|
||||
// }
|
||||
|
||||
fmt.Println("# Checking in on SunGrow...")
|
||||
err = Cmd.SunGrowArgs(cmd, args)
|
||||
if err != nil {
|
||||
// var psId int64
|
||||
// psId, Cmd.Error = Cmd.SunGrow.GetPsId()
|
||||
// if err != nil {
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("# Found SunGrow device %d\n", psId)
|
||||
// // Also getPowerStatistics, getHouseholdStoragePsReport, getPsList, getUpTimePoint,
|
||||
// ep := Cmd.SunGrow.QueryDevice(psId)
|
||||
// if ep.IsError() {
|
||||
// Cmd.Error = ep.GetError()
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// data := ep.GetData()
|
||||
// fmt.Printf("# Adding %d entries to HASSIO.\n", len(data.Entries))
|
||||
// for i, r := range data.Entries {
|
||||
// fmt.Printf("%s ", r.PointId)
|
||||
// Cmd.Error = foo.SensorPublishConfig(r.PointId, r.PointName, r.Unit, i)
|
||||
// if err != nil {
|
||||
// break
|
||||
// }
|
||||
// Cmd.Error = foo.SensorPublishState(r.PointId, r.Value)
|
||||
// if err != nil {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// fmt.Println()
|
||||
// if err != nil {
|
||||
// break
|
||||
// }
|
||||
|
||||
Cmd.Error = MqttCron()
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
var psId int64
|
||||
psId, err = Cmd.SunGrow.GetPsId()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Printf("# Found SunGrow device %d\n", psId)
|
||||
// Also getPowerStatistics, getHouseholdStoragePsReport, getPsList, getUpTimePoint,
|
||||
ep := Cmd.SunGrow.QueryDevice(psId)
|
||||
if ep.IsError() {
|
||||
err = ep.GetError()
|
||||
break
|
||||
}
|
||||
|
||||
data := ep.GetData()
|
||||
fmt.Printf("# Adding %d entries to HASSIO.\n", len(data.Entries))
|
||||
for i, r := range data.Entries {
|
||||
fmt.Printf("%s ", r.PointId)
|
||||
err = foo.SensorPublishConfig(r.PointId, r.PointName, r.Unit, i)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
err = foo.SensorPublishState(r.PointId, r.Value)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Println("# Starting ticker...")
|
||||
LogPrintDate("Starting ticker...\n")
|
||||
updateCounter := 0
|
||||
timer := time.NewTicker(60 * time.Second)
|
||||
for t := range timer.C {
|
||||
if updateCounter < 5 {
|
||||
updateCounter++
|
||||
fmt.Printf("Wait: %d - %s\n", updateCounter, t.String())
|
||||
LogPrintDate("Sleeping: %d\n", updateCounter)
|
||||
continue
|
||||
}
|
||||
|
||||
updateCounter = 0
|
||||
fmt.Printf("Update: %s\n", t.String())
|
||||
ep = Cmd.SunGrow.QueryDevice(psId)
|
||||
if ep.IsError() {
|
||||
err = ep.GetError()
|
||||
LogPrintDate("Update: %s\n", t.String())
|
||||
Cmd.Error = MqttCron()
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
data = ep.GetData()
|
||||
for _, r := range data.Entries {
|
||||
// fmt.Printf("%s ", r.PointId)
|
||||
err = foo.SensorPublishState(r.PointId, r.Value)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
// fmt.Println()
|
||||
// ep = Cmd.SunGrow.QueryDevice(psId)
|
||||
// if ep.IsError() {
|
||||
// Cmd.Error = ep.GetError()
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// data = ep.GetData()
|
||||
// for _, r := range data.Entries {
|
||||
// // fmt.Printf("%s ", r.PointId)
|
||||
// Cmd.Error = foo.SensorPublishState(r.PointId, r.Value)
|
||||
// if err != nil {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// // fmt.Println()
|
||||
}
|
||||
if err != nil {
|
||||
}
|
||||
|
||||
return Cmd.Error
|
||||
}
|
||||
|
||||
func cmdMqttSyncFunc(_ *cobra.Command, args []string) error {
|
||||
|
||||
for range Only.Once {
|
||||
// */1 * * * * /dir/command args args
|
||||
cronString := "*/5 * * * *"
|
||||
if len(args) > 0 {
|
||||
cronString = strings.Join(args[0:5], " ")
|
||||
cronString = strings.ReplaceAll(cronString, ".", "*")
|
||||
}
|
||||
|
||||
Cron.Scheduler = gocron.NewScheduler(time.UTC)
|
||||
Cron.Scheduler = Cron.Scheduler.Cron(cronString)
|
||||
Cron.Scheduler = Cron.Scheduler.SingletonMode()
|
||||
|
||||
Cmd.Error = MqttCron()
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
Cron.Job, Cmd.Error = Cron.Scheduler.Do(MqttCron)
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// switch {
|
||||
// case len(args) == 0:
|
||||
// Cmd.Error = cmd.Help()
|
||||
//
|
||||
// case args[0] == "all":
|
||||
// // Cmd.Error = Cmd.GoogleUpdate()
|
||||
//
|
||||
// default:
|
||||
// fmt.Println("Unknown sub-command.")
|
||||
// _ = cmd.Help()
|
||||
// }
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func toggle(v string) string {
|
||||
switch v {
|
||||
case "OFF":
|
||||
v = "ON"
|
||||
case "ON":
|
||||
v = "OFF"
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func randoPercent() string {
|
||||
t := time.Now()
|
||||
min := 0
|
||||
max := t.Second()
|
||||
i := (rand.Intn(max - min) + min) * t.Minute() // / float64(max)
|
||||
return fmt.Sprintf("%.2f", (float64(i) / 3600) * 100)
|
||||
}
|
||||
|
||||
func randoKWh() string {
|
||||
t := time.Now()
|
||||
min := 0
|
||||
max := t.Minute()
|
||||
i := (rand.Intn(max - min) + min) * t.Second() // / float64(max)
|
||||
return fmt.Sprintf("%.2f", (float64(i) / 3600) * 11000)
|
||||
}
|
||||
|
||||
func cmdMqttSyncFunc(cmd *cobra.Command, args []string) {
|
||||
for range Only.Once {
|
||||
switch {
|
||||
case len(args) == 0:
|
||||
Cmd.Error = cmd.Help()
|
||||
|
||||
case args[0] == "all":
|
||||
// Cmd.Error = Cmd.GoogleUpdate()
|
||||
|
||||
default:
|
||||
fmt.Println("Unknown sub-command.")
|
||||
_ = cmd.Help()
|
||||
LogPrintDate("Created job schedule using '%s'\n", cronString)
|
||||
Cron.Scheduler.StartBlocking()
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return Cmd.Error
|
||||
}
|
||||
|
||||
func MqttCron() error {
|
||||
for range Only.Once {
|
||||
if Cmd.Mqtt == nil {
|
||||
Cmd.Error = errors.New("mqtt not available")
|
||||
break
|
||||
}
|
||||
|
||||
if Cmd.SunGrow == nil {
|
||||
Cmd.Error = errors.New("sungrow not available")
|
||||
break
|
||||
}
|
||||
|
||||
if Cmd.Mqtt.IsFirstRun() {
|
||||
Cmd.Mqtt.UnsetFirstRun()
|
||||
} else {
|
||||
time.Sleep(time.Second * 40) // Takes up to 40 seconds for data to come in.
|
||||
}
|
||||
|
||||
// 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() {
|
||||
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)
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
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)
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
Cmd.Mqtt.LastRefresh = time.Now()
|
||||
|
||||
if Cmd.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if Cmd.Error != nil {
|
||||
LogPrintDate("Error: %s\n", Cmd.Error)
|
||||
}
|
||||
return Cmd.Error
|
||||
}
|
||||
|
||||
|
||||
// func toggle(v string) string {
|
||||
// switch v {
|
||||
// case "OFF":
|
||||
// v = "ON"
|
||||
// case "ON":
|
||||
// v = "OFF"
|
||||
// }
|
||||
// return v
|
||||
// }
|
||||
//
|
||||
// func randoPercent() string {
|
||||
// t := time.Now()
|
||||
// min := 0
|
||||
// max := t.Second()
|
||||
// i := (rand.Intn(max - min) + min) * t.Minute() // / float64(max)
|
||||
// return fmt.Sprintf("%.2f", (float64(i) / 3600) * 100)
|
||||
// }
|
||||
//
|
||||
// func randoKWh() string {
|
||||
// t := time.Now()
|
||||
// min := 0
|
||||
// max := t.Minute()
|
||||
// i := (rand.Intn(max - min) + min) * t.Second() // / float64(max)
|
||||
// return fmt.Sprintf("%.2f", (float64(i) / 3600) * 11000)
|
||||
// }
|
||||
|
@ -22,6 +22,11 @@ const (
|
||||
flagApiLastLogin = "token-expiry"
|
||||
flagApiOutputType = "out"
|
||||
|
||||
flagMqttUsername = "mqtt-user"
|
||||
flagMqttPassword = "mqtt-password"
|
||||
flagMqttHost = "mqtt-host"
|
||||
flagMqttPort = "mqtt-port"
|
||||
|
||||
flagGoogleSheet = "google-sheet"
|
||||
flagGoogleSheetUpdate = "update"
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"GoSungrow/iSolarCloud/AppService/login"
|
||||
"GoSungrow/lsgo"
|
||||
"GoSungrow/mmGit"
|
||||
"GoSungrow/mmMqtt"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
@ -20,6 +21,7 @@ var DefaultAreas = []string{"all"}
|
||||
type CommandArgs struct {
|
||||
SunGrow *iSolarCloud.SunGrow
|
||||
Git *mmGit.Git
|
||||
Mqtt *mmMqtt.Mqtt
|
||||
|
||||
ConfigDir string
|
||||
CacheDir string
|
||||
@ -41,6 +43,12 @@ type CommandArgs struct {
|
||||
ApiTokenFile string
|
||||
ApiOutputType string
|
||||
|
||||
// HASSIO MQTT
|
||||
MqttUsername string
|
||||
MqttPassword string
|
||||
MqttHost string
|
||||
MqttPort string
|
||||
|
||||
// Google sheets
|
||||
GoogleSheet string
|
||||
GoogleSheetUpdate bool
|
||||
|
16
cmd/viper.go
@ -69,6 +69,11 @@ func openConfig() error {
|
||||
rootViper.SetDefault(flagApiPassword, defaultPassword)
|
||||
rootViper.SetDefault(flagApiAppKey, Cmd.ApiAppKey)
|
||||
|
||||
rootViper.SetDefault(flagMqttUsername, Cmd.MqttUsername)
|
||||
rootViper.SetDefault(flagMqttPassword, Cmd.MqttPassword)
|
||||
rootViper.SetDefault(flagMqttHost, Cmd.MqttHost)
|
||||
rootViper.SetDefault(flagMqttPort, Cmd.MqttPort)
|
||||
|
||||
rootViper.SetDefault(flagGoogleSheet, Cmd.GoogleSheet)
|
||||
rootViper.SetDefault(flagGoogleSheetUpdate, Cmd.GoogleSheetUpdate)
|
||||
|
||||
@ -122,6 +127,11 @@ func writeConfig() error {
|
||||
rootViper.Set(flagApiPassword, Cmd.ApiPassword)
|
||||
rootViper.Set(flagApiAppKey, Cmd.ApiAppKey)
|
||||
|
||||
rootViper.Set(flagMqttUsername, Cmd.MqttUsername)
|
||||
rootViper.Set(flagMqttPassword, Cmd.MqttPassword)
|
||||
rootViper.Set(flagMqttHost, Cmd.MqttHost)
|
||||
rootViper.Set(flagMqttPort, Cmd.MqttPort)
|
||||
|
||||
rootViper.Set(flagGoogleSheet, Cmd.GoogleSheet)
|
||||
rootViper.Set(flagGoogleSheetUpdate, Cmd.GoogleSheetUpdate)
|
||||
|
||||
@ -159,6 +169,12 @@ func readConfig() error {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Api UserPassword: %v\n", rootViper.Get(flagApiPassword))
|
||||
_, _ = fmt.Fprintln(os.Stderr)
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "HASSIO mqtt Username: %v\n", rootViper.Get(flagMqttUsername))
|
||||
_, _ = fmt.Fprintf(os.Stderr, "HASSIO mqtt Password: %v\n", rootViper.Get(flagMqttPassword))
|
||||
_, _ = fmt.Fprintf(os.Stderr, "HASSIO mqtt Host: %v\n", rootViper.Get(flagMqttHost))
|
||||
_, _ = fmt.Fprintf(os.Stderr, "HASSIO mqtt Port: %v\n", rootViper.Get(flagMqttPort))
|
||||
_, _ = fmt.Fprintln(os.Stderr)
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Git Repo URL: %v\n", rootViper.Get(flagGitRepo))
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Git Repo Dir: %v\n", rootViper.Get(flagGitRepoDir))
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Git Repo User: %v\n", rootViper.Get(flagGitUsername))
|
||||
|
184
docs/AllPoints.txt
Normal file
@ -0,0 +1,184 @@
|
||||
+----------+----------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+----------------------------+------+
|
||||
| p83106 | Load Power | kW |
|
||||
| p13019 | Internal Air Temperature | ℃ |
|
||||
| p13121 | Total Export Active Power | kW |
|
||||
| p13149 | Purchased Power | kW |
|
||||
| p13003 | Total DC Power | kW |
|
||||
| p13142 | Battery Health (SOH) | % |
|
||||
| p13143 | Battery Temperature | ℃ |
|
||||
| p13150 | Battery Discharging Power | kW |
|
||||
| p13126 | Battery Charging Power | kW |
|
||||
| p13141 | Battery Level (SOC) | % |
|
||||
+----------+----------------------------+------+
|
||||
+----------+---------------------------------+--------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+---------------------------------+--------+
|
||||
| p83012 | P-radiation-H | W/㎡ |
|
||||
| p83013 | Daily Irradiation | Wh/m2 |
|
||||
| p83239 | Total field reactive power | Mvar |
|
||||
| p83001 | Inverter AC Power Normalization | kW/kWp |
|
||||
| p13007 | Grid Frequency | Hz |
|
||||
| p13013 | Total Power Factor | |
|
||||
| p13018 | Total Apparent Power | VA |
|
||||
| p13160 | Array Insulation Resistance | kΩ |
|
||||
+----------+---------------------------------+--------+
|
||||
+----------+---------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+---------------------------+------+
|
||||
| p13019 | Internal Air Temperature | ℃ |
|
||||
| p13143 | Battery Temperature | ℃ |
|
||||
| p83016 | Plant Ambient Temperature | ℃ |
|
||||
| p83017 | Plant Module Temperature | ℃ |
|
||||
+----------+---------------------------+------+
|
||||
+----------+-----------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+-----------------+------+
|
||||
| p13161 | Bus Voltage | V |
|
||||
| p13001 | MPPT1 Voltage | V |
|
||||
| p13158 | Phase B Voltage | V |
|
||||
| p13159 | Phase C Voltage | V |
|
||||
| p13105 | MPPT2 Voltage | V |
|
||||
| p13138 | Battery Voltage | V |
|
||||
| p13157 | Phase A Voltage | V |
|
||||
+----------+-----------------+------+
|
||||
+----------+--------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+--------------------------------+------+
|
||||
| p13002 | MPPT1 Current | A |
|
||||
| p13009 | Phase B Current | A |
|
||||
| p13162 | Max. Charging Current (BMS) | A |
|
||||
| p18063 | Phase B Backup Current | A |
|
||||
| p18062 | Phase A Backup Current | A |
|
||||
| p18064 | Phase C Backup Current | A |
|
||||
| p13008 | Phase A Current | A |
|
||||
| p13010 | Phase C Current | A |
|
||||
| p13139 | Battery Current | A |
|
||||
| p13163 | Max. Discharging Current (BMS) | A |
|
||||
| p13106 | MPPT2 Current | A |
|
||||
+----------+--------------------------------+------+
|
||||
+----------+----------------------------------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+----------------------------------------------------------+------+
|
||||
| p83007 | Meter PR | % |
|
||||
| p83010 | Inverter PR | % |
|
||||
| p83019 | Power/Installed Power of Plant | % |
|
||||
| p83129 | Battery SOC | % |
|
||||
| p83420 | Current Power/Inverter Installed Capacity | % |
|
||||
| p83023 | Plant PR | % |
|
||||
| p83252 | Battery Level (SOC) | % |
|
||||
| p83419 | Daily Highest Inverter Power/Inverter Installed Capacity | % |
|
||||
| p13144 | Daily Self-consumption Rate | % |
|
||||
| p13141 | Battery Level (SOC) | % |
|
||||
| p13142 | Battery Health (SOH) | % |
|
||||
+----------+----------------------------------------------------------+------+
|
||||
+----------+--------------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+--------------------------------------+------+
|
||||
| p83241 | Total field charge capacity | MWh |
|
||||
| p83242 | Total field discharge capacity | MWh |
|
||||
| p83235 | Total field chargeable energy | MWh |
|
||||
| p83236 | Total field dischargeable energy | MWh |
|
||||
| p83243 | Total field daily charge capacity | MWh |
|
||||
| p83244 | Total field daily discharge capacity | MWh |
|
||||
+----------+--------------------------------------+------+
|
||||
+----------+---------------------------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+---------------------------------------------------+------+
|
||||
| p83233 | Total field maximum rechargeable power | MW |
|
||||
| p83234 | Total field maximum dischargeable power | MW |
|
||||
| p83237 | Total field energy storage maximum reactive power | MW |
|
||||
| p83238 | Total field energy storage active power | MW |
|
||||
+----------+---------------------------------------------------+------+
|
||||
+----------+---------------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+---------------------------------------+------+
|
||||
| p83033 | Plant Power | kW |
|
||||
| p83549 | Grid active power | kW |
|
||||
| p83002 | Inverter AC Power | kW |
|
||||
| p83032 | Meter AC Power | kW |
|
||||
| p83128 | Total Active Power of Optical Storage | kW |
|
||||
| p83106 | Load Power | kW |
|
||||
| p13011 | Total Active Power | kW |
|
||||
| p13121 | Total Export Active Power | kW |
|
||||
| p13150 | Battery Discharging Power | kW |
|
||||
| p13149 | Purchased Power | kW |
|
||||
| p18068 | Total Backup Power | kW |
|
||||
| p13126 | Battery Charging Power | kW |
|
||||
| p18067 | Phase C Backup Power | kW |
|
||||
| p13003 | Total DC Power | kW |
|
||||
| p13119 | Total Load Active Power | kW |
|
||||
| p18065 | Phase A Backup Power | kW |
|
||||
| p18066 | Phase B Backup Power | kW |
|
||||
+----------+---------------------------------------+------+
|
||||
+----------+------------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+------------------------------------+------+
|
||||
| p83005 | Daily Equivalent Hours of Meter | h |
|
||||
| p83008 | Daily Equivalent Hours of Inverter | h |
|
||||
| p83025 | Plant Equivalent Hours | h |
|
||||
+----------+------------------------------------+------+
|
||||
+----------+-----------------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+-----------------------------------------+------+
|
||||
| p13029 | Daily Battery Discharging Energy | kWh |
|
||||
| p13116 | Daily Load Energy Consumption from PV | kWh |
|
||||
| p13137 | Total Load Energy Consumption from PV | kWh |
|
||||
| p13174 | Daily Battery Charging Energy from PV | kWh |
|
||||
| p13199 | Daily Load Energy Consumption | kWh |
|
||||
| p13130 | Total Load Energy Consumption | kWh |
|
||||
| p13134 | Total PV Yield | kWh |
|
||||
| p13140 | Battery Capacity(kWh) | kWh |
|
||||
| p13173 | Daily Feed-in Energy (PV) | kWh |
|
||||
| p13175 | Total Feed-in Energy (PV) | kWh |
|
||||
| p13176 | Total Battery Charging Energy from PV | kWh |
|
||||
| p13125 | Total Feed-in Energy | kWh |
|
||||
| p13028 | Daily Battery Charging Energy | kWh |
|
||||
| p13035 | Total Battery Discharging Energy | kWh |
|
||||
| p13148 | Total Purchased Energy | kWh |
|
||||
| p13034 | Total Battery Charging Energy | kWh |
|
||||
| p13112 | Daily PV Yield | kWh |
|
||||
| p13122 | Daily Feed-in Energy | kWh |
|
||||
| p13147 | Daily Purchased Energy | kWh |
|
||||
| p83119 | Daily Feed-in Energy (PV) | kWh |
|
||||
| p83124 | Total Load Energy Consumption | kWh |
|
||||
| p83100 | Total Load Energy Consumption from PV | kWh |
|
||||
| p83102 | Daily Purchased Energy | kWh |
|
||||
| p83105 | Total Purchased Energy | kWh |
|
||||
| p83021 | Accumulative Power Consumption by Meter | kWh |
|
||||
| p83022 | Daily Yield of Plant | kWh |
|
||||
| p83072 | Daily Feed-in Energy | kWh |
|
||||
| p83004 | Inverter Total Yield | kWh |
|
||||
| p83006 | Meter Daily Yield | kWh |
|
||||
| p83009 | Daily Yield by Inverter | kWh |
|
||||
| p83011 | Meter E-daily Consumption | kWh |
|
||||
| p83018 | Daily Yield (Theoretical) | kWh |
|
||||
| p83020 | Meter Total Yield | kWh |
|
||||
| p83024 | Plant Total Yield | kWh |
|
||||
| p83097 | Daily Load Energy Consumption from PV | kWh |
|
||||
| p83075 | Total Feed-in Energy | kWh |
|
||||
+----------+-----------------------------------------+------+
|
||||
+----------+---------------------------------------+------+
|
||||
| Point Id | Description | Unit |
|
||||
+----------+---------------------------------------+------+
|
||||
| p83002 | Inverter AC Power | kW |
|
||||
| p83006 | Meter Daily Yield | kWh |
|
||||
| p83549 | Grid active power | kW |
|
||||
| p83011 | Meter E-daily Consumption | kWh |
|
||||
| p83022 | Daily Yield of Plant | kWh |
|
||||
| p83033 | Plant Power | kW |
|
||||
| p83119 | Daily Feed-in Energy (PV) | kWh |
|
||||
| p83032 | Meter AC Power | kW |
|
||||
| p83097 | Daily Load Energy Consumption from PV | kWh |
|
||||
| p83102 | Daily Purchased Energy | kWh |
|
||||
| p83072 | Daily Feed-in Energy | kWh |
|
||||
| p13028 | Daily Battery Charging Energy | kWh |
|
||||
| p13122 | Daily Feed-in Energy | kWh |
|
||||
| p13112 | Daily PV Yield | kWh |
|
||||
| p13116 | Daily Load Energy Consumption from PV | kWh |
|
||||
| p13147 | Daily Purchased Energy | kWh |
|
||||
| p13173 | Daily Feed-in Energy (PV) | kWh |
|
||||
| p13174 | Daily Battery Charging Energy from PV | kWh |
|
||||
| p13199 | Daily Load Energy Consumption | kWh |
|
||||
+----------+---------------------------------------+------+
|
BIN
docs/IMG-7925.png
Normal file
After Width: | Height: | Size: 438 KiB |
BIN
docs/IMG-7926.png
Normal file
After Width: | Height: | Size: 374 KiB |
BIN
docs/IMG-7927.png
Normal file
After Width: | Height: | Size: 355 KiB |
BIN
docs/IMG-7928.png
Normal file
After Width: | Height: | Size: 386 KiB |
BIN
docs/IMG-7929.png
Normal file
After Width: | Height: | Size: 364 KiB |
BIN
docs/IMG-7930.png
Normal file
After Width: | Height: | Size: 313 KiB |
BIN
docs/IMG-7931.png
Normal file
After Width: | Height: | Size: 400 KiB |
BIN
docs/IMG-7932.png
Normal file
After Width: | Height: | Size: 405 KiB |
BIN
docs/IMG-7933.png
Normal file
After Width: | Height: | Size: 421 KiB |
1
docs/data/js/0jes.b7d561b8.js
Normal file
115
docs/data/js/app.b8da93af.js
Normal file
1
docs/data/js/chunk-496f.480f6ce1.js
Normal file
1
docs/data/js/chunk-58ab.9ad9549d.js
Normal file
80661
docs/data/js/chunk-58ab.9ad9549d.js.2
Normal file
16
docs/data/js/chunk-7961.0a3e86b0.2.js
Normal file
1
docs/data/js/chunk-commons.d3d0b178.js
Normal file
1
docs/data/js/chunk-d500.bcf00f23.2.js
Normal file
1
docs/data/js/chunk-echarts.44267f0d.2.js
Normal file
1
docs/data/js/chunk-elementUI.adbc7cae.2.js
Normal file
81899
docs/data/js/chunk-f7a0.cf7e90ce.js.2
Normal file
67
docs/data/js/chunk-sungrowUtils.fb8bd9a6.js
Normal file
7
docs/data/js/nc.js
Normal file
1
docs/data/js/runtime~app.1dd9624a.js
Normal file
1
docs/data/js/zhuge.js
Normal file
@ -1,8 +1,10 @@
|
||||
package getPsDetailWithPsType
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/iSolarCloud/api"
|
||||
"GoSungrow/iSolarCloud/api/apiReflect"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@ -165,3 +167,250 @@ func (e *ResultData) IsValid() error {
|
||||
//
|
||||
// return err
|
||||
//}
|
||||
|
||||
func (e *EndPoint) GetDataTable() output.Table {
|
||||
var table output.Table
|
||||
|
||||
for range Only.Once {
|
||||
table = output.NewTable()
|
||||
e.Error = table.SetTitle("")
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
_ = table.SetHeader(
|
||||
"Date",
|
||||
"Point Id",
|
||||
"Description",
|
||||
"Value",
|
||||
"(Unit)",
|
||||
"(Unit)",
|
||||
)
|
||||
|
||||
now := api.TimeNowString()
|
||||
|
||||
keys := api.GetStructKeys(e.Response.ResultData)
|
||||
for _, n := range keys.Sort() {
|
||||
p := api.GetPoint(e.Response.ResultData.PsPsKey, n)
|
||||
if p != nil {
|
||||
_ = table.AddRow(
|
||||
now,
|
||||
api.NameDevicePoint(e.Response.ResultData.PsPsKey, n),
|
||||
p.Description,
|
||||
keys[n].Value,
|
||||
p.Unit,
|
||||
keys[n].Unit,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
_ = table.AddRow(
|
||||
now,
|
||||
api.NameDevicePoint(e.Response.ResultData.PsPsKey, n),
|
||||
api.UpperCase(n),
|
||||
keys[n].Value,
|
||||
keys[n].Unit,
|
||||
keys[n].Unit,
|
||||
)
|
||||
}
|
||||
|
||||
if len(e.Response.ResultData.StorageInverterData) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
for _, sid := range e.Response.ResultData.StorageInverterData {
|
||||
keys = api.GetStructKeys(sid)
|
||||
for _, n := range keys.Sort() {
|
||||
p := api.GetPoint(sid.PsKey, n)
|
||||
if p != nil {
|
||||
_ = table.AddRow(
|
||||
now,
|
||||
api.NameDevicePoint(sid.PsKey, n),
|
||||
p.Description,
|
||||
keys[n].Value,
|
||||
p.Unit,
|
||||
keys[n].Unit,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
_ = table.AddRow(
|
||||
now,
|
||||
api.NameDevicePoint(sid.PsKey, n),
|
||||
api.UpperCase(n),
|
||||
keys[n].Value,
|
||||
keys[n].Unit,
|
||||
keys[n].Unit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// table.InitGraph(output.GraphRequest {
|
||||
// Title: "",
|
||||
// TimeColumn: output.SetInteger(1),
|
||||
// SearchColumn: output.SetInteger(2),
|
||||
// NameColumn: output.SetInteger(4),
|
||||
// ValueColumn: output.SetInteger(5),
|
||||
// UnitsColumn: output.SetInteger(6),
|
||||
// SearchString: output.SetString(""),
|
||||
// MinLeftAxis: output.SetFloat(0),
|
||||
// MaxLeftAxis: output.SetFloat(0),
|
||||
// })
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
func (e *EndPoint) GetData() api.Data {
|
||||
var ret api.Data
|
||||
|
||||
// for range Only.Once {
|
||||
// index := 0
|
||||
// for _, d := range e.Response.ResultData.PageList {
|
||||
// for _, p := range d.PointData {
|
||||
// if p.Unit == "W" {
|
||||
// fv, err := strconv.ParseFloat(p.Value, 64)
|
||||
// fv = fv / 1000
|
||||
// if err == nil {
|
||||
// p.Value = fmt.Sprintf("%.3f", fv)
|
||||
// p.Unit = "kW"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ret.Entries = append(ret.Entries, api.DataEntry {
|
||||
// Date: api.NewDateTime(p.TimeStamp),
|
||||
// PointId: api.GetAreaPointName(d.PsKey, p.PointID),
|
||||
// PointGroupName: p.PointGroupName,
|
||||
// PointName: p.PointName,
|
||||
// Value: p.Value,
|
||||
// Unit: p.Unit,
|
||||
// ValueType: api.GetPointType(d.PsKey, p.PointID),
|
||||
// Index: index,
|
||||
// })
|
||||
//
|
||||
// index++
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (e *EndPoint) GetPsKeys() []string {
|
||||
ret := []string{e.Response.ResultData.PsPsKey}
|
||||
for _, l := range e.Response.ResultData.StorageInverterData {
|
||||
ret = append(ret, l.PsKey)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// ChargingDischargingPowerMap
|
||||
// Co2ReduceTotal
|
||||
// CoalReduceTotal
|
||||
// ConnectType
|
||||
// CurrPower
|
||||
// DesignCapacity
|
||||
// EnergyScheme
|
||||
// GcjLatitude
|
||||
// GcjLongitude
|
||||
// HasAmmeter
|
||||
// HouseholdInverterData
|
||||
// InstallerPsFaultStatus
|
||||
// IsHaveEsInverter
|
||||
// IsSingleInverter
|
||||
// IsTransformSystem
|
||||
// Latitude
|
||||
// LoadPowerMap
|
||||
// LoadPowerMapVirgin
|
||||
// Longitude
|
||||
// MapLatitude
|
||||
// MapLongitude
|
||||
// MeterReduceTotal
|
||||
// MobleTel
|
||||
// MonthEnergy
|
||||
// MonthEnergyVirgin
|
||||
// MonthIncome
|
||||
// NegativeLoadMsg
|
||||
// OwnerPsFaultStatus
|
||||
// P83081Map
|
||||
// P83081MapVirgin
|
||||
// P83102Map
|
||||
// P83102MapVirgin
|
||||
// P83102Percent
|
||||
// P83118Map
|
||||
// P83118MapVirgin
|
||||
// P83119Map
|
||||
// P83119MapVirgin
|
||||
// P83120Map
|
||||
// P83120MapVirgin
|
||||
// P83122
|
||||
// P83124Map
|
||||
// P83124MapVirgin
|
||||
// P83202Map
|
||||
// P83202MapVirgin
|
||||
// P83532MapVirgin
|
||||
// PowerChargeSetted
|
||||
// PowerGridPowerMap
|
||||
// PowerGridPowerMapVirgin
|
||||
// PsCountryID
|
||||
// PsDeviceType
|
||||
// PsFaultStatus
|
||||
// PsHealthStatus
|
||||
// PsLocation
|
||||
// PsName
|
||||
// PsPsKey
|
||||
// PsState
|
||||
// PsType
|
||||
// PvPowerMap
|
||||
// PvPowerMapVirgin
|
||||
// RobotNumSweepCapacity
|
||||
// Num
|
||||
// SweepCapacity
|
||||
// }
|
||||
// SelfConsumptionOffsetReminder
|
||||
// So2ReduceTotal
|
||||
// StorageInverterData
|
||||
// CommunicationDevSn
|
||||
// DevStatus
|
||||
// DeviceCode
|
||||
// DeviceModelCode
|
||||
// DeviceName
|
||||
// DeviceState
|
||||
// DeviceType
|
||||
// DrmStatus
|
||||
// DrmStatusName
|
||||
// EnergyFlow
|
||||
// HasAmmeter
|
||||
// InstallerDevFaultStatus
|
||||
// InverterSn
|
||||
// OwnerDevFaultStatus
|
||||
// P13003Map
|
||||
// P13003MapVirgin
|
||||
// P13119Map
|
||||
// P13119MapVirgin
|
||||
// P13121Map
|
||||
// P13121MapVirgin
|
||||
// P13126Map
|
||||
// P13126MapVirgin
|
||||
// P13141
|
||||
// P13149Map
|
||||
// P13149MapVirgin
|
||||
// P13150Map
|
||||
// P13150MapVirgin
|
||||
// PsKey
|
||||
// UUID
|
||||
// }
|
||||
// TodayEnergy
|
||||
// TodayEnergyVirgin
|
||||
// TodayIncome
|
||||
// TotalEnergy
|
||||
// TotalEnergyVirgin
|
||||
// TotalIncome
|
||||
// TreeReduceTotal
|
||||
// ValidFlag
|
||||
// WgsLatitude
|
||||
// WgsLongitude
|
||||
// ZfzyMap
|
||||
// ZfzyMapVirgin
|
||||
// ZjzzMap
|
||||
// ZjzzMapVirgin
|
||||
|
@ -21,13 +21,13 @@ type SunGrowAuth struct {
|
||||
UserAccount string
|
||||
UserPassword string
|
||||
TokenFile string
|
||||
Token string
|
||||
// Token string
|
||||
Force bool
|
||||
|
||||
lastLogin time.Time
|
||||
newToken bool
|
||||
retry int
|
||||
err error
|
||||
lastLogin time.Time
|
||||
newToken bool
|
||||
// retry int
|
||||
err error
|
||||
}
|
||||
|
||||
func (a *SunGrowAuth) Verify() error {
|
||||
@ -61,11 +61,11 @@ func (a *SunGrowAuth) Verify() error {
|
||||
func (e *EndPoint) Login(auth *SunGrowAuth) error {
|
||||
for range Only.Once {
|
||||
e.Auth = auth
|
||||
e.Request.RequestData = RequestData{
|
||||
e.Request.RequestData = RequestData {
|
||||
UserAccount: auth.UserAccount,
|
||||
UserPassword: auth.UserPassword,
|
||||
}
|
||||
e.Request.RequestCommon = api.RequestCommon{
|
||||
e.Request.RequestCommon = api.RequestCommon {
|
||||
Appkey: auth.AppKey,
|
||||
SysCode: "900",
|
||||
}
|
||||
@ -81,29 +81,28 @@ func (e *EndPoint) Login(auth *SunGrowAuth) error {
|
||||
}
|
||||
|
||||
if auth.Force {
|
||||
e.Auth.Token = ""
|
||||
e.Response.ResultData.Token = ""
|
||||
// e.Error = os.Remove(filepath.Join(e.ApiRoot.GetCacheDir(), e.CacheFilename()))
|
||||
// if e.Error != nil {
|
||||
// break
|
||||
// }
|
||||
e.SetTokenInvalid()
|
||||
}
|
||||
|
||||
if e.IsTokenValid() {
|
||||
break
|
||||
}
|
||||
|
||||
foo := Assert(e.Call())
|
||||
e.Error = foo.GetError()
|
||||
ep := Assert(e.Call())
|
||||
e.Error = ep.GetError()
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
e.Request = foo.Request
|
||||
e.Response = foo.Response
|
||||
e.Request = ep.Request
|
||||
e.Response = ep.Response
|
||||
e.Auth.lastLogin = time.Now()
|
||||
|
||||
if e.IsTokenInvalid() {
|
||||
break
|
||||
}
|
||||
|
||||
// e.Auth.UserAccount = e.Response.ResultData.UserAccount
|
||||
e.Auth.Token = e.Response.ResultData.Token
|
||||
e.Auth.lastLogin, _ = time.Parse(LastLoginDateFormat, e.Response.ResultData.LoginLastDate)
|
||||
e.Auth.newToken = true
|
||||
|
||||
e.Error = e.saveToken()
|
||||
if e.Error != nil {
|
||||
@ -114,38 +113,68 @@ func (e *EndPoint) Login(auth *SunGrowAuth) error {
|
||||
return e.Error
|
||||
}
|
||||
|
||||
func (e *EndPoint) IsTokenInvalid() bool {
|
||||
func (e *EndPoint) SetTokenInvalid() {
|
||||
for range Only.Once {
|
||||
if e.Token() == "" {
|
||||
e.Auth.newToken = true
|
||||
break
|
||||
}
|
||||
if e.HoursFromLastLogin() > TokenValidHours {
|
||||
e.Auth.newToken = true
|
||||
break
|
||||
}
|
||||
// e.Auth.Token = ""
|
||||
e.Response.ResultData.Token = ""
|
||||
e.Auth.newToken = true
|
||||
// e.Error = os.Remove(filepath.Join(e.ApiRoot.GetCacheDir(), e.CacheFilename()))
|
||||
// if e.Error != nil {
|
||||
// break
|
||||
// }
|
||||
}
|
||||
|
||||
return e.Auth.newToken
|
||||
}
|
||||
|
||||
// func (e *EndPoint) SetTokenValid(t string) {
|
||||
// // e.Auth.Token = t
|
||||
// e.Response.ResultData.Token = t
|
||||
// e.Auth.newToken = true
|
||||
// }
|
||||
|
||||
func (e *EndPoint) IsTokenValid() bool {
|
||||
var ok bool
|
||||
for range Only.Once {
|
||||
if e.Token() == "" {
|
||||
if e.Response.ResponseCommon.IsTokenInvalid() {
|
||||
e.SetTokenInvalid()
|
||||
break
|
||||
}
|
||||
if e.HoursFromLastLogin() > TokenValidHours {
|
||||
break
|
||||
}
|
||||
ok = true
|
||||
}
|
||||
|
||||
return ok
|
||||
if e.Response.ResultData.Token == "" {
|
||||
e.SetTokenInvalid()
|
||||
break
|
||||
}
|
||||
|
||||
if e.HoursFromLastLogin() > TokenValidHours {
|
||||
e.SetTokenInvalid()
|
||||
break
|
||||
}
|
||||
|
||||
e.Auth.newToken = false
|
||||
}
|
||||
return !e.Auth.newToken
|
||||
}
|
||||
|
||||
func (e *EndPoint) HoursFromLastLogin() time.Duration {
|
||||
return time.Now().Sub(e.Auth.lastLogin)
|
||||
func (e *EndPoint) IsTokenInvalid() bool {
|
||||
return !e.IsTokenValid()
|
||||
// for range Only.Once {
|
||||
// if e.Response.ResponseCommon.IsTokenInvalid() {
|
||||
// e.Auth.newToken = true
|
||||
// break
|
||||
// }
|
||||
// if e.Response.ResultData.Token == "" {
|
||||
// e.Auth.newToken = true
|
||||
// break
|
||||
// }
|
||||
// if e.HoursFromLastLogin() > TokenValidHours {
|
||||
// e.Auth.newToken = true
|
||||
// break
|
||||
// }
|
||||
// e.Auth.newToken = false
|
||||
// }
|
||||
// return e.Auth.newToken
|
||||
}
|
||||
|
||||
func (e *EndPoint) HoursFromLastLogin() float64 {
|
||||
return time.Now().Sub(e.Auth.lastLogin).Hours()
|
||||
}
|
||||
|
||||
func (e *EndPoint) HasTokenChanged() bool {
|
||||
@ -180,17 +209,12 @@ func (e *EndPoint) readTokenFile() error {
|
||||
e.Auth.TokenFile = e.GetFilePath()
|
||||
|
||||
// e.Error = e.ApiReadDataFile(e.Auth.TokenFile, &e.Response.ResultData)
|
||||
e.Error = output.FileRead(e.Auth.TokenFile, &e.Response.ResultData)
|
||||
e.Error = output.FileRead(e.Auth.TokenFile, &e.Response)
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
e.Response.ResultData.Msg = ""
|
||||
e.Response.ResultMsg = ""
|
||||
e.Response.ResultCode = ""
|
||||
|
||||
e.Auth.Token = e.Token()
|
||||
if e.Auth.Token == "" {
|
||||
if e.Token() == "" {
|
||||
e.Auth.newToken = true
|
||||
break
|
||||
}
|
||||
@ -212,7 +236,7 @@ func (e *EndPoint) saveToken() error {
|
||||
for range Only.Once {
|
||||
e.Auth.TokenFile = e.GetFilePath()
|
||||
|
||||
e.Error = output.FileWrite(e.Auth.TokenFile, e.Response.ResultData, output.DefaultFileMode)
|
||||
e.Error = output.FileWrite(e.Auth.TokenFile, e.Response, output.DefaultFileMode)
|
||||
// e.Error = e.ApiWriteDataFile(e.Auth.TokenFile, e.Response.ResultData, 0644)
|
||||
if e.Error != nil {
|
||||
break
|
||||
|
@ -41,8 +41,8 @@ type Response struct {
|
||||
|
||||
// Init - Used to initialize a new endpoint instance. Usually called from an area.
|
||||
func Init(apiRoot api.Web) EndPoint {
|
||||
return EndPoint{
|
||||
EndPointStruct: api.EndPointStruct{
|
||||
return EndPoint {
|
||||
EndPointStruct: api.EndPointStruct {
|
||||
ApiRoot: apiRoot,
|
||||
Area: api.GetArea(EndPoint{}),
|
||||
Name: api.GetName(EndPoint{}),
|
||||
@ -51,16 +51,16 @@ func Init(apiRoot api.Web) EndPoint {
|
||||
Response: Response{},
|
||||
Error: nil,
|
||||
},
|
||||
Auth: &SunGrowAuth{
|
||||
Auth: &SunGrowAuth {
|
||||
AppKey: "",
|
||||
UserAccount: "",
|
||||
UserPassword: "",
|
||||
TokenFile: DefaultAuthTokenFile,
|
||||
Token: "",
|
||||
// Token: "",
|
||||
Force: false,
|
||||
lastLogin: time.Time{},
|
||||
newToken: false,
|
||||
retry: 0,
|
||||
// retry: 0,
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"GoSungrow/iSolarCloud/api/apiReflect"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const Url = "/v1/devService/queryDeviceList"
|
||||
@ -221,16 +222,32 @@ func (e *EndPoint) GetDataTable() output.Table {
|
||||
"Date",
|
||||
"Point Id",
|
||||
"Point Group Name",
|
||||
"Point Name",
|
||||
"Description",
|
||||
"Value",
|
||||
"Unit",
|
||||
)
|
||||
|
||||
for _, d := range e.Response.ResultData.PageList {
|
||||
for _, p := range d.PointData {
|
||||
p.Value, p.Unit = api.DivideByThousandIfRequired(p.Value, p.Unit)
|
||||
// gp := api.GetPointInt("", p.PointID)
|
||||
// if gp != nil {
|
||||
// _ = table.AddRow(
|
||||
// api.NewDateTime(p.TimeStamp).PrintFull(),
|
||||
// api.NameDevicePointInt(d.PsKey, p.PointID),
|
||||
// p.PointGroupName,
|
||||
// p.PointName,
|
||||
// gp.Description,
|
||||
// p.Value,
|
||||
// p.Unit,
|
||||
// gp.Unit,
|
||||
// )
|
||||
// continue
|
||||
// }
|
||||
|
||||
_ = table.AddRow(
|
||||
api.NewDateTime(p.TimeStamp).PrintFull(),
|
||||
fmt.Sprintf("%s.%d", d.PsKey, p.PointID),
|
||||
api.NameDevicePointInt(d.PsKey, p.PointID),
|
||||
p.PointGroupName,
|
||||
p.PointName,
|
||||
p.Value,
|
||||
@ -255,51 +272,37 @@ func (e *EndPoint) GetDataTable() output.Table {
|
||||
return table
|
||||
}
|
||||
|
||||
func (e *EndPoint) GetData() api.Data {
|
||||
var ret api.Data
|
||||
|
||||
type Data struct {
|
||||
// Headers DataHeaders
|
||||
Entries []DataEntry
|
||||
}
|
||||
// type DataHeaders struct {
|
||||
// Date string
|
||||
// PointId string
|
||||
// PointGroupName string
|
||||
// PointName string
|
||||
// Value string
|
||||
// Unit string
|
||||
// }
|
||||
type DataEntry struct {
|
||||
Date api.DateTime `json:"date"`
|
||||
PointId string `json:"point_id"`
|
||||
PointGroupName string `json:"point_group_name"`
|
||||
PointName string `json:"point_name"`
|
||||
Value string `json:"value"`
|
||||
Unit string `json:"unit"`
|
||||
}
|
||||
func (e *EndPoint) GetData() Data {
|
||||
var ret Data
|
||||
for range Only.Once {
|
||||
// ret.Headers = DataHeaders {
|
||||
// Date: "Date",
|
||||
// PointId: "Point Id",
|
||||
// PointGroupName: "Point Group Name",
|
||||
// PointName: "Point Name",
|
||||
// Value: "Value",
|
||||
// Unit: "Unit",
|
||||
// }
|
||||
|
||||
index := 0
|
||||
for _, d := range e.Response.ResultData.PageList {
|
||||
for _, p := range d.PointData {
|
||||
ret.Entries = append(ret.Entries, DataEntry {
|
||||
if p.Unit == "W" {
|
||||
fv, err := strconv.ParseFloat(p.Value, 64)
|
||||
fv = fv / 1000
|
||||
if err == nil {
|
||||
p.Value = fmt.Sprintf("%.3f", fv)
|
||||
p.Unit = "kW"
|
||||
}
|
||||
}
|
||||
|
||||
ret.Entries = append(ret.Entries, api.DataEntry {
|
||||
Date: api.NewDateTime(p.TimeStamp),
|
||||
PointId: fmt.Sprintf("%s.%d", d.PsKey, p.PointID),
|
||||
PointId: api.NameDevicePointInt(d.PsKey, p.PointID),
|
||||
PointGroupName: p.PointGroupName,
|
||||
PointName: p.PointName,
|
||||
Value: p.Value,
|
||||
Unit: p.Unit,
|
||||
ValueType: api.GetPointInt(d.PsKey, p.PointID),
|
||||
Index: index,
|
||||
})
|
||||
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
@ -1,16 +1,18 @@
|
||||
package queryDeviceRealTimeDataByPsKeys
|
||||
|
||||
import (
|
||||
"GoSungrow/iSolarCloud/api"
|
||||
"GoSungrow/iSolarCloud/api/apiReflect"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const Url = "/v1/devService/queryDeviceRealTimeDataByPsKeys"
|
||||
const Disabled = true
|
||||
const Disabled = false
|
||||
|
||||
type RequestData struct {
|
||||
// DeviceType string `json:"device_type" required:"true"`
|
||||
PsKeyList string `json:"ps_key_list" required:"true"`
|
||||
}
|
||||
|
||||
func (rd RequestData) IsValid() error {
|
||||
@ -56,3 +58,87 @@ func (e *ResultData) IsValid() error {
|
||||
//
|
||||
// return err
|
||||
//}
|
||||
|
||||
func (e *EndPoint) GetDataTable() output.Table {
|
||||
var table output.Table
|
||||
|
||||
// for range Only.Once {
|
||||
// table = output.NewTable()
|
||||
// e.Error = table.SetTitle("")
|
||||
// if e.Error != nil {
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// _ = table.SetHeader(
|
||||
// "Date",
|
||||
// "Point Id",
|
||||
// "Point Group Name",
|
||||
// "Point Name",
|
||||
// "Value",
|
||||
// "Unit",
|
||||
// )
|
||||
//
|
||||
// for _, d := range e.Response.ResultData.PageList {
|
||||
// for _, p := range d.PointData {
|
||||
// _ = table.AddRow(
|
||||
// api.NewDateTime(p.TimeStamp).PrintFull(),
|
||||
// fmt.Sprintf("%s.%d", d.PsKey, p.PointID),
|
||||
// p.PointGroupName,
|
||||
// p.PointName,
|
||||
// p.Value,
|
||||
// p.Unit,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// table.InitGraph(output.GraphRequest {
|
||||
// Title: "",
|
||||
// TimeColumn: output.SetInteger(1),
|
||||
// SearchColumn: output.SetInteger(2),
|
||||
// NameColumn: output.SetInteger(4),
|
||||
// ValueColumn: output.SetInteger(5),
|
||||
// UnitsColumn: output.SetInteger(6),
|
||||
// SearchString: output.SetString(""),
|
||||
// MinLeftAxis: output.SetFloat(0),
|
||||
// MaxLeftAxis: output.SetFloat(0),
|
||||
// })
|
||||
//
|
||||
// }
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
func (e *EndPoint) GetData() api.Data {
|
||||
var ret api.Data
|
||||
|
||||
// for range Only.Once {
|
||||
// index := 0
|
||||
// for _, d := range e.Response.ResultData.PageList {
|
||||
// for _, p := range d.PointData {
|
||||
// if p.Unit == "W" {
|
||||
// fv, err := strconv.ParseFloat(p.Value, 64)
|
||||
// fv = fv / 1000
|
||||
// if err == nil {
|
||||
// p.Value = fmt.Sprintf("%.3f", fv)
|
||||
// p.Unit = "kW"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ret.Entries = append(ret.Entries, api.DataEntry {
|
||||
// Date: api.NewDateTime(p.TimeStamp),
|
||||
// PointId: api.GetAreaPointName(d.PsKey, p.PointID),
|
||||
// PointGroupName: p.PointGroupName,
|
||||
// PointName: p.PointName,
|
||||
// Value: p.Value,
|
||||
// Unit: p.Unit,
|
||||
// ValueType: api.GetPointType(d.PsKey, p.PointID),
|
||||
// Index: index,
|
||||
// })
|
||||
//
|
||||
// index++
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return ret
|
||||
}
|
||||
|
107
iSolarCloud/WebAppService/getMqttConfigInfoByAppkey/data.go
Normal file
@ -0,0 +1,107 @@
|
||||
package getMqttConfigInfoByAppkey
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/iSolarCloud/api/apiReflect"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
||||
const Url = "/v1/commonService/getMqttConfigInfoByAppkey"
|
||||
const Disabled = false
|
||||
|
||||
const (
|
||||
WebAppKey = "B0455FBE7AA0328DB57B59AA729F05D8"
|
||||
LoginAppKey = "93D72E60331ABDCDC7B39ADC2D1F32B3"
|
||||
)
|
||||
|
||||
type RequestData struct {
|
||||
AppKey string `json:"app_key" required:"true"`
|
||||
}
|
||||
|
||||
// IsValid Checks for validity of results data.
|
||||
func (rd RequestData) IsValid() error {
|
||||
return apiReflect.VerifyOptionsRequired(rd)
|
||||
}
|
||||
|
||||
// Help provides more info to the user on request JSON fields.
|
||||
func (rd RequestData) Help() string {
|
||||
ret := fmt.Sprintf("")
|
||||
return ret
|
||||
}
|
||||
|
||||
// ResultData holds data returned from the API.
|
||||
type ResultData struct {
|
||||
Code string `json:"code"`
|
||||
MqttPassword string `json:"mqtt_password"`
|
||||
MqttRsaPublicKey string `json:"mqtt_rsa_public_key"`
|
||||
MqttType string `json:"mqtt_type"`
|
||||
MqttURLList []string `json:"mqtt_url_list"`
|
||||
MqttURLListLan []string `json:"mqtt_url_list_lan"`
|
||||
MqttUsername string `json:"mqtt_username"`
|
||||
}
|
||||
|
||||
// IsValid Checks for validity of results data.
|
||||
func (e *ResultData) IsValid() error {
|
||||
var err error
|
||||
// switch {
|
||||
// case e.Dummy == "":
|
||||
// break
|
||||
// default:
|
||||
// err = errors.New(fmt.Sprintf("unknown error '%s'", e.Dummy))
|
||||
// }
|
||||
return err
|
||||
}
|
||||
|
||||
// type DecodeResultData ResultData
|
||||
//
|
||||
// func (e *ResultData) UnmarshalJSON(data []byte) error {
|
||||
// var err error
|
||||
//
|
||||
// for range Only.Once {
|
||||
// if len(data) == 0 {
|
||||
// break
|
||||
// }
|
||||
// var pd DecodeResultData
|
||||
//
|
||||
// // Store ResultData
|
||||
// _ = json.Unmarshal(data, &pd)
|
||||
// e.Dummy = pd.Dummy
|
||||
// }
|
||||
//
|
||||
// return err
|
||||
// }
|
||||
|
||||
func (e *EndPoint) GetDataTable() output.Table {
|
||||
var table output.Table
|
||||
|
||||
for range Only.Once {
|
||||
table = output.NewTable()
|
||||
e.Error = table.SetTitle("")
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
e.Error = table.SetHeader(
|
||||
"AppKey",
|
||||
"Name",
|
||||
"Value",
|
||||
)
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// @TODO - Think about providing an apiReflect function that does this automatically.
|
||||
_ = table.AddRow(e.Request.AppKey, "Code", e.Response.ResultData.Code)
|
||||
_ = table.AddRow(e.Request.AppKey, "Mqtt Username", e.Response.ResultData.MqttUsername)
|
||||
_ = table.AddRow(e.Request.AppKey, "Mqtt Password", e.Response.ResultData.MqttPassword)
|
||||
_ = table.AddRow(e.Request.AppKey, "Mqtt Rsa Public Key", e.Response.ResultData.MqttRsaPublicKey)
|
||||
_ = table.AddRow(e.Request.AppKey, "Mqtt Type", e.Response.ResultData.MqttType)
|
||||
_ = table.AddRow(e.Request.AppKey, "Mqtt URL List", e.Response.ResultData.MqttURLList)
|
||||
_ = table.AddRow(e.Request.AppKey, "Mqtt URL List Lan", e.Response.ResultData.MqttURLListLan)
|
||||
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
360
iSolarCloud/WebAppService/getMqttConfigInfoByAppkey/struct.go
Normal file
@ -0,0 +1,360 @@
|
||||
// Package getMqttConfigInfoByAppkey
|
||||
// - This file is auto-generated from the update_all.sh script.
|
||||
// Do not modify anything here. Any changes to this EndPoint should be made in the data.go file.
|
||||
// The only exception is the AppService.login package.
|
||||
package getMqttConfigInfoByAppkey
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/iSolarCloud/api"
|
||||
"GoSungrow/iSolarCloud/api/apiReflect"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
// api.EndPoint - Import API endpoint interface
|
||||
var _ api.EndPoint = (*EndPoint)(nil)
|
||||
|
||||
// EndPoint - Holds the request, response and web method structures.
|
||||
type EndPoint struct {
|
||||
api.EndPointStruct
|
||||
Request Request
|
||||
Response Response
|
||||
}
|
||||
|
||||
// Request - Holds the api.RequestCommon and user RequestData structures. See data.go for request fields.
|
||||
type Request struct {
|
||||
api.RequestCommon
|
||||
RequestData
|
||||
}
|
||||
|
||||
// Response - Holds the api.ResponseCommon and endpoint specific ResultData structures. See data.go for response fields.
|
||||
type Response struct {
|
||||
api.ResponseCommon
|
||||
ResultData ResultData `json:"result_data"`
|
||||
}
|
||||
|
||||
// Init - Used to initialize a new endpoint instance. Usually called from an area.
|
||||
func Init(apiRoot api.Web) EndPoint {
|
||||
return EndPoint{
|
||||
EndPointStruct: api.EndPointStruct{
|
||||
ApiRoot: apiRoot,
|
||||
Area: api.GetArea(EndPoint{}),
|
||||
Name: api.GetName(EndPoint{}),
|
||||
Url: api.SetUrl(Url),
|
||||
Request: Request{},
|
||||
Response: Response{},
|
||||
Error: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ******************************************************************************** //
|
||||
|
||||
// Methods not scoped by api.EndPoint interface type
|
||||
|
||||
// Init - If the endpoint needs to be re-initialized.
|
||||
func (e EndPoint) Init(apiRoot api.Web) *EndPoint {
|
||||
ret := Init(apiRoot)
|
||||
return &ret
|
||||
}
|
||||
|
||||
// GetRequest - Get the Request structure as scoped by this endpoint.
|
||||
func (e EndPoint) GetRequest() Request {
|
||||
return e.Request
|
||||
}
|
||||
|
||||
// GetResponse - Get the Response structure as scoped by this endpoint.
|
||||
func (e EndPoint) GetResponse() Response {
|
||||
return e.Response
|
||||
}
|
||||
|
||||
// Assert - Used to obtain locally scoped EndPoint methods, (not visible from api.EndPoint).
|
||||
//goland:noinspection GoUnusedExportedFunction
|
||||
func Assert(e api.EndPoint) EndPoint {
|
||||
return e.(EndPoint)
|
||||
}
|
||||
|
||||
// AssertResultData - Used to obtain locally scoped ResultData methods, (not visible from api.EndPoint).
|
||||
//goland:noinspection GoUnusedExportedFunction
|
||||
func AssertResultData(e api.EndPoint) ResultData {
|
||||
return e.(EndPoint).Response.ResultData
|
||||
}
|
||||
|
||||
|
||||
// ******************************************************************************** //
|
||||
|
||||
// Methods defined by api.EndPoint interface type
|
||||
|
||||
// Help - Return help information on the JSON structure used to populate RequestData.
|
||||
func (e EndPoint) Help() string {
|
||||
ret := apiReflect.HelpOptions(e.Request.RequestData)
|
||||
ret += fmt.Sprintf("JSON request:\t%s\n", e.GetRequestJson())
|
||||
ret += e.Request.Help()
|
||||
return ret
|
||||
}
|
||||
|
||||
// IsDisabled - Is this endpoint disabled? See data.go Disabled constant.
|
||||
func (e EndPoint) IsDisabled() bool {
|
||||
return Disabled
|
||||
}
|
||||
|
||||
// GetArea - Returns the API area that this EndPoint is located.
|
||||
func (e EndPoint) GetArea() api.AreaName {
|
||||
return e.Area
|
||||
}
|
||||
|
||||
// GetName - Returns the API EndPoint name.
|
||||
func (e EndPoint) GetName() api.EndPointName {
|
||||
return e.Name
|
||||
}
|
||||
|
||||
// GetUrl - Returns the API EndPoint url.
|
||||
func (e EndPoint) GetUrl() api.EndPointUrl {
|
||||
return e.Url
|
||||
}
|
||||
|
||||
// Call - Once RequestData is populated, this will access the iSolarCloud API and populate ResultData.
|
||||
func (e EndPoint) Call() api.EndPoint {
|
||||
return e.ApiRoot.Get(e)
|
||||
}
|
||||
|
||||
// GetJsonData - Get the JSON representation of ResultData, either as condensed or "pretty".
|
||||
func (e EndPoint) GetJsonData(raw bool) output.Json {
|
||||
if raw {
|
||||
return output.Json(e.ApiRoot.Body)
|
||||
} else {
|
||||
return output.GetAsPrettyJson(e.Response.ResultData)
|
||||
}
|
||||
}
|
||||
|
||||
// SetError - Set the error code for this EndPoint.
|
||||
func (e EndPoint) SetError(format string, a ...interface{}) api.EndPoint {
|
||||
e.EndPointStruct.Error = errors.New(fmt.Sprintf(format, a...))
|
||||
return e
|
||||
}
|
||||
|
||||
// GetError - Get the error code for this EndPoint.
|
||||
func (e EndPoint) GetError() error {
|
||||
return e.EndPointStruct.Error
|
||||
}
|
||||
|
||||
// IsError - Is there an error?
|
||||
func (e EndPoint) IsError() bool {
|
||||
if e.Error != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReadDataFile - Read a JSON file and populate the ResultData structure.
|
||||
// (File names will default to AREA-ENDPOINT.json )
|
||||
func (e EndPoint) ReadDataFile() error {
|
||||
// return e.FileRead("", &e.Response.ResultData)
|
||||
return e.ApiReadDataFile(&e.Response.ResultData)
|
||||
}
|
||||
|
||||
// WriteDataFile - Write to a file, the contents of ResultData as JSON.
|
||||
// (File names will default to AREA-ENDPOINT.json )
|
||||
func (e EndPoint) WriteDataFile() error {
|
||||
// return e.FileWrite("", e.Response.ResultData, output.DefaultFileMode)
|
||||
return e.ApiWriteDataFile(e.Response.ResultData)
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************************************
|
||||
|
||||
// SetRequest - Save an interface reference as either api.RequestCommon or RequestData.
|
||||
func (e EndPoint) SetRequest(ref interface{}) api.EndPoint {
|
||||
for range Only.Once {
|
||||
if apiReflect.GetPkgType(ref) == "api.RequestCommon" {
|
||||
e.Request.RequestCommon = ref.(api.RequestCommon)
|
||||
break
|
||||
}
|
||||
|
||||
if apiReflect.GetType(ref) == "RequestData" {
|
||||
e.Request.RequestData = ref.(RequestData)
|
||||
e.Error = e.IsRequestValid()
|
||||
break
|
||||
}
|
||||
|
||||
e.Error = apiReflect.DoPkgTypesMatch(e.Request, ref)
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
e.Request = ref.(Request)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// SetRequestByJson - Save RequestData from a JSON string.
|
||||
func (e EndPoint) SetRequestByJson(j output.Json) api.EndPoint {
|
||||
for range Only.Once {
|
||||
e.Error = json.Unmarshal([]byte(j), &e.Request.RequestData)
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
e.Error = e.IsRequestValid()
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// RequestRef - Return the locally scoped Request structure.
|
||||
func (e EndPoint) RequestRef() interface{} {
|
||||
return e.Request
|
||||
}
|
||||
|
||||
// GetRequestJson - Return the Request structure as a JSON string.
|
||||
func (e EndPoint) GetRequestJson() output.Json {
|
||||
return output.GetAsJson(e.Request.RequestData)
|
||||
}
|
||||
|
||||
// // GetFingerprint - Used to formulate cache filenames.
|
||||
// func (e EndPoint) GetFingerprint() string {
|
||||
// return apiReflect.GetFingerprint(e.Request.RequestData)
|
||||
// }
|
||||
|
||||
// IsRequestValid - Is api.RequestCommon and RequestData valid?
|
||||
func (e EndPoint) IsRequestValid() error {
|
||||
for range Only.Once {
|
||||
// req := e.GetRequest()
|
||||
// req := e.Request.RequestCommon
|
||||
e.Error = e.Request.RequestCommon.IsValid()
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
e.Error = e.Request.RequestData.IsValid()
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return e.Error
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************************************
|
||||
|
||||
// SetResponse - Save a JSON string to the Response structure.
|
||||
// (Used by the web call method.)
|
||||
func (e EndPoint) SetResponse(ref []byte) api.EndPoint {
|
||||
for range Only.Once {
|
||||
e.Error = json.Unmarshal(ref, &e.Response)
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// GetResponseJson - Return the Response structure as a JSON string.
|
||||
func (e EndPoint) GetResponseJson() output.Json {
|
||||
return output.GetAsPrettyJson(e.Response)
|
||||
}
|
||||
|
||||
// ResponseRef - Return the locally scoped Response structure.
|
||||
func (e EndPoint) ResponseRef() interface{} {
|
||||
return e.Response
|
||||
}
|
||||
|
||||
// IsResponseValid - Is api.ResponseCommon and ResultData valid?
|
||||
func (e EndPoint) IsResponseValid() error {
|
||||
for range Only.Once {
|
||||
e.Error = e.Response.ResponseCommon.IsValid()
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
e.Error = e.Response.ResultData.IsValid()
|
||||
if e.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return e.Error
|
||||
}
|
||||
|
||||
// String - Stringer method for this EndPoint.
|
||||
func (e EndPoint) String() string {
|
||||
return output.GetEndPointString(e)
|
||||
}
|
||||
|
||||
// RequestString - Return the Request structure as a human-readable string.
|
||||
func (e EndPoint) RequestString() string {
|
||||
return output.GetRequestString(e.Request)
|
||||
}
|
||||
|
||||
// ResponseString - Return the Response structure as a human-readable string.
|
||||
func (e EndPoint) ResponseString() string {
|
||||
return output.GetRequestString(e.Response)
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************************************
|
||||
|
||||
// MarshalJSON - Marshall the EndPoint.
|
||||
func (e EndPoint) MarshalJSON() ([]byte, error) {
|
||||
return api.MarshalJSON(e)
|
||||
|
||||
// return json.Marshal(&struct {
|
||||
// Area string `json:"area"`
|
||||
// EndPoint string `json:"endpoint"`
|
||||
// Host string `json:"api_host"`
|
||||
// Url string `json:"endpoint_url"`
|
||||
// Request interface{} `json:"request"`
|
||||
// Response interface{} `json:"response"`
|
||||
// }{
|
||||
// Area: string(e.Area),
|
||||
// EndPoint: string(e.Name),
|
||||
// Host: e.ApiRoot.Url.String(),
|
||||
// Url: e.Url.String(),
|
||||
// Request: e.Request,
|
||||
// Response: e.Response,
|
||||
// })
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************************************
|
||||
|
||||
// RequestFingerprint - Check if a cache file exists for this EndPoint.
|
||||
func (e EndPoint) RequestFingerprint() string {
|
||||
return e.ApiFingerprint(e.Request.RequestData)
|
||||
}
|
||||
|
||||
// CacheFilename - Check if a cache file exists for this EndPoint.
|
||||
func (e EndPoint) CacheFilename() string {
|
||||
return e.ApiCacheFilename(e.Request.RequestData)
|
||||
}
|
||||
|
||||
// // CheckCache - Check if a cache file exists for this EndPoint.
|
||||
// func (e EndPoint) CheckCache() bool {
|
||||
// return e.ApiCheckCache(e.Request.RequestData)
|
||||
// }
|
||||
//
|
||||
// // ReadCache - Read a cache file and return it as an EndPoint structure.
|
||||
// func (e EndPoint) ReadCache() api.EndPoint {
|
||||
// e.Error = e.ApiReadCache(e.Request.RequestData, &e)
|
||||
// return e
|
||||
// }
|
||||
//
|
||||
// // WriteCache - Write this EndPoint structure out to a cache file.
|
||||
// func (e EndPoint) WriteCache() error {
|
||||
// return e.ApiWriteCache(e.Request.RequestData, e)
|
||||
// }
|
||||
|
||||
// SetCacheTimeout - Set the cache timeout for this EndPoint. (Defaults to 1 hour.)
|
||||
func (e EndPoint) SetCacheTimeout(duration time.Duration) api.EndPoint {
|
||||
e.ApiRoot.SetCacheTimeout(duration)
|
||||
return e
|
||||
}
|
||||
|
||||
// GetCacheTimeout - Return the cache timeout for this EndPoint.
|
||||
func (e EndPoint) GetCacheTimeout() time.Duration {
|
||||
return e.ApiRoot.GetCacheTimeout()
|
||||
}
|
@ -78,6 +78,7 @@ import (
|
||||
"GoSungrow/iSolarCloud/WebAppService/getInverterFactoryList"
|
||||
"GoSungrow/iSolarCloud/WebAppService/getInverterInfo"
|
||||
"GoSungrow/iSolarCloud/WebAppService/getLoadCurveList"
|
||||
"GoSungrow/iSolarCloud/WebAppService/getMqttConfigInfoByAppkey"
|
||||
"GoSungrow/iSolarCloud/WebAppService/getMultiPowers"
|
||||
"GoSungrow/iSolarCloud/WebAppService/getOndutyQuery"
|
||||
"GoSungrow/iSolarCloud/WebAppService/getOperateTicketUserList"
|
||||
@ -214,6 +215,10 @@ func Init(apiRoot api.Web) Area {
|
||||
api.GetName(queryUserCurveTemplateData.EndPoint{}): queryUserCurveTemplateData.Init(apiRoot),
|
||||
api.GetName(getDeviceUuid.EndPoint{}): getDeviceUuid.Init(apiRoot), // /v1/devService/getDeviceUuid}
|
||||
|
||||
// Discovered from Chrome Dev Tools
|
||||
api.GetName(getMqttConfigInfoByAppkey.EndPoint{}): getMqttConfigInfoByAppkey.Init(apiRoot), // /v1/devService/getDeviceUuid}
|
||||
|
||||
|
||||
api.GetName(addMaterial.EndPoint{}): addMaterial.Init(apiRoot), // /v1/otherService/addMaterial}
|
||||
api.GetName(addOptTicketInfo.EndPoint{}): addOptTicketInfo.Init(apiRoot), // /v1/faultService/addOptTicketInfo}
|
||||
api.GetName(addSpareParts.EndPoint{}): addSpareParts.Init(apiRoot), // /v1/otherService/addSpareParts}
|
||||
@ -409,6 +414,7 @@ func Init(apiRoot api.Web) Area {
|
||||
// ****************************************
|
||||
// Methods not scoped by api.EndPoint interface type
|
||||
|
||||
//goland:noinspection GoUnusedExportedFunction
|
||||
func GetAreaName() string {
|
||||
return string(api.GetArea(Area{}))
|
||||
}
|
||||
@ -427,6 +433,7 @@ func (a Area) GetEndPoint(name api.EndPointName) api.EndPoint {
|
||||
// ****************************************
|
||||
// Methods scoped by api.Area interface type
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) Init(apiRoot *api.Web) api.AreaStruct {
|
||||
panic("implement me")
|
||||
}
|
||||
@ -442,30 +449,37 @@ func (a Area) GetEndPoints() api.TypeEndPoints {
|
||||
return a.EndPoints
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) Call(name api.EndPointName) output.Json {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) SetRequest(name api.EndPointName, ref interface{}) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) GetRequest(name api.EndPointName) output.Json {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) GetResponse(name api.EndPointName) output.Json {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) GetData(name api.EndPointName) output.Json {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) IsValid(name api.EndPointName) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func (a Area) GetError(name api.EndPointName) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
143
iSolarCloud/api/apiReflect/field.go
Normal file
@ -0,0 +1,143 @@
|
||||
// Package apiReflect - Snaffooed from https://github.com/fatih/structs
|
||||
package apiReflect
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
|
||||
var (
|
||||
errNotExported = errors.New("field is not exported")
|
||||
errNotSettable = errors.New("field is not settable")
|
||||
)
|
||||
|
||||
// Field represents a single struct field that encapsulates high level
|
||||
// functions around the field.
|
||||
type Field struct {
|
||||
value reflect.Value
|
||||
field reflect.StructField
|
||||
defaultTag string
|
||||
}
|
||||
|
||||
// Tag returns the value associated with key in the tag string. If there is no
|
||||
// such key in the tag, Tag returns the empty string.
|
||||
func (f *Field) Tag(key string) string {
|
||||
return f.field.Tag.Get(key)
|
||||
}
|
||||
|
||||
// Value returns the underlying value of the field. It panics if the field
|
||||
// is not exported.
|
||||
func (f *Field) Value() interface{} {
|
||||
return f.value.Interface()
|
||||
}
|
||||
|
||||
// IsEmbedded returns true if the given field is an anonymous field (embedded)
|
||||
func (f *Field) IsEmbedded() bool {
|
||||
return f.field.Anonymous
|
||||
}
|
||||
|
||||
// IsExported returns true if the given field is exported.
|
||||
func (f *Field) IsExported() bool {
|
||||
return f.field.PkgPath == ""
|
||||
}
|
||||
|
||||
// IsZero returns true if the given field is not initialized (has a zero value).
|
||||
// It panics if the field is not exported.
|
||||
func (f *Field) IsZero() bool {
|
||||
zero := reflect.Zero(f.value.Type()).Interface()
|
||||
current := f.Value()
|
||||
|
||||
return reflect.DeepEqual(current, zero)
|
||||
}
|
||||
|
||||
// Name returns the name of the given field
|
||||
func (f *Field) Name() string {
|
||||
return f.field.Name
|
||||
}
|
||||
|
||||
// Kind returns the fields kind, such as "string", "map", "bool", etc ..
|
||||
func (f *Field) Kind() reflect.Kind {
|
||||
return f.value.Kind()
|
||||
}
|
||||
|
||||
// Set sets the field to given value v. It returns an error if the field is not
|
||||
// settable (not addressable or not exported) or if the given value's type
|
||||
// doesn't match the fields type.
|
||||
func (f *Field) Set(val interface{}) error {
|
||||
// we can't set unexported fields, so be sure this field is exported
|
||||
if !f.IsExported() {
|
||||
return errNotExported
|
||||
}
|
||||
|
||||
// do we get here? not sure...
|
||||
if !f.value.CanSet() {
|
||||
return errNotSettable
|
||||
}
|
||||
|
||||
given := reflect.ValueOf(val)
|
||||
|
||||
if f.value.Kind() != given.Kind() {
|
||||
return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind())
|
||||
}
|
||||
|
||||
f.value.Set(given)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Zero sets the field to its zero value. It returns an error if the field is not
|
||||
// settable (not addressable or not exported).
|
||||
func (f *Field) Zero() error {
|
||||
zero := reflect.Zero(f.value.Type()).Interface()
|
||||
return f.Set(zero)
|
||||
}
|
||||
|
||||
// Fields returns a slice of Fields. This is particular handy to get the fields
|
||||
// of a nested struct . A struct tag with the content of "-" ignores the
|
||||
// checking of that particular field. Example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field *http.Request `structs:"-"`
|
||||
//
|
||||
// It panics if field is not exported or if field's kind is not struct
|
||||
func (f *Field) Fields() []*Field {
|
||||
return getFields(f.value, f.defaultTag)
|
||||
}
|
||||
|
||||
// Field returns the field from a nested struct. It panics if the nested struct
|
||||
// is not exported or if the field was not found.
|
||||
func (f *Field) Field(name string) *Field {
|
||||
field, ok := f.FieldOk(name)
|
||||
if !ok {
|
||||
panic("field not found")
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// FieldOk returns the field from a nested struct. The boolean returns whether
|
||||
// the field was found (true) or not (false).
|
||||
func (f *Field) FieldOk(name string) (*Field, bool) {
|
||||
value := &f.value
|
||||
// value must be settable so we need to make sure it holds the address of the
|
||||
// variable and not a copy, so we can pass the pointer to strctVal instead of a
|
||||
// copy (which is not assigned to any variable, hence not settable).
|
||||
// see "https://blog.golang.org/laws-of-reflection#TOC_8."
|
||||
if f.value.Kind() != reflect.Ptr {
|
||||
a := f.value.Addr()
|
||||
value = &a
|
||||
}
|
||||
v := strctVal(value.Interface())
|
||||
t := v.Type()
|
||||
|
||||
field, ok := t.FieldByName(name)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &Field{
|
||||
field: field,
|
||||
value: v.FieldByName(name),
|
||||
}, true
|
||||
}
|
@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"strconv"
|
||||
|
||||
// "github.com/google/uuid"
|
||||
"path/filepath"
|
||||
@ -626,6 +627,92 @@ func GetOptionsRequired(ref interface{}) Required {
|
||||
return ret
|
||||
}
|
||||
|
||||
type StructKey struct {
|
||||
Name string
|
||||
JsonName string
|
||||
JsonValue string
|
||||
Required string
|
||||
Value string
|
||||
Type reflect.Type
|
||||
Interface interface{}
|
||||
}
|
||||
type StructKeys map[string]StructKey
|
||||
|
||||
//goland:noinspection GoUnusedFunction,GoUnusedExportedFunction
|
||||
func GetStructKeys(ref interface{}, keys ...string) StructKeys {
|
||||
ret := make(StructKeys)
|
||||
|
||||
s := New(ref)
|
||||
if len(keys) == 0 {
|
||||
keys = s.Names()
|
||||
}
|
||||
|
||||
keyMap := make(map[string]bool)
|
||||
for _, k := range keys {
|
||||
keyMap[k] = true
|
||||
}
|
||||
|
||||
// n := s.Names()
|
||||
// fmt.Printf("%v\n", n)
|
||||
//
|
||||
// n2 := s.Name()
|
||||
// fmt.Printf("%v\n", n2)
|
||||
//
|
||||
// n3 := s.TagName
|
||||
// fmt.Printf("%v\n", n3)
|
||||
//
|
||||
// n4 := s.Fields()
|
||||
// fmt.Printf("%v\n", n4)
|
||||
//
|
||||
// n5 := s.Map()
|
||||
// fmt.Printf("%v\n", n5)
|
||||
//
|
||||
// n6 := s.Values()
|
||||
// fmt.Printf("%v\n", n6)
|
||||
//
|
||||
// n7 := s.Field("")
|
||||
// fmt.Printf("%v\n", n7)
|
||||
|
||||
for _, k := range New(ref).Fields() {
|
||||
if _, ok := keyMap[k.Name()]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
jValue := ""
|
||||
value := ""
|
||||
switch k.value.Type().Name() {
|
||||
case "string":
|
||||
value = k.Value().(string)
|
||||
case "int":
|
||||
v := k.Value().(int)
|
||||
value = strconv.FormatInt(int64(v), 10)
|
||||
case "int64":
|
||||
value = strconv.FormatInt(k.Value().(int64), 10)
|
||||
case "float64":
|
||||
value = strconv.FormatFloat(k.Value().(float64), 'f', 6, 64)
|
||||
default:
|
||||
j, e := json.Marshal(k.Value())
|
||||
if e == nil {
|
||||
jValue = string(j)
|
||||
} else {
|
||||
jValue = fmt.Sprintf("%v", k.Value())
|
||||
}
|
||||
}
|
||||
|
||||
ret[k.Name()] = StructKey {
|
||||
Name: k.Name(),
|
||||
JsonName: k.Tag("json"),
|
||||
JsonValue: jValue,
|
||||
Value: value,
|
||||
Required: k.Tag("required"),
|
||||
Type: k.value.Type(),
|
||||
Interface: k.Value(),
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *Required) IsRequired(field string) bool {
|
||||
var ok bool
|
||||
for _, f := range *r {
|
||||
|
585
iSolarCloud/api/apiReflect/structs.go
Normal file
@ -0,0 +1,585 @@
|
||||
// Package apiReflect - Snaffooed from https://github.com/fatih/structs
|
||||
// Package apiReflect contains various utilities functions to work with structs.
|
||||
package apiReflect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultTagName is the default tag name for struct fields which provides
|
||||
// a more granular to tweak certain structs. Lookup the necessary functions
|
||||
// for more info.
|
||||
DefaultTagName = "structs" // struct's field default tag name
|
||||
)
|
||||
|
||||
// Struct encapsulates a struct type to provide several high level functions
|
||||
// around the struct.
|
||||
type Struct struct {
|
||||
raw interface{}
|
||||
value reflect.Value
|
||||
TagName string
|
||||
}
|
||||
|
||||
// New returns a new *Struct with the struct s. It panics if the s's kind is
|
||||
// not struct.
|
||||
func New(s interface{}) *Struct {
|
||||
return &Struct{
|
||||
raw: s,
|
||||
value: strctVal(s),
|
||||
TagName: DefaultTagName,
|
||||
}
|
||||
}
|
||||
|
||||
// Map converts the given struct to a map[string]interface{}, where the keys
|
||||
// of the map are the field names and the values of the map the associated
|
||||
// values of the fields. The default key string is the struct field name but
|
||||
// can be changed in the struct field's tag value. The "structs" key in the
|
||||
// struct's field tag value is the key name. Example:
|
||||
//
|
||||
// // Field appears in map as key "myName".
|
||||
// Name string `structs:"myName"`
|
||||
//
|
||||
// A tag value with the content of "-" ignores that particular field. Example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field bool `structs:"-"`
|
||||
//
|
||||
// A tag value with the content of "string" uses the stringer to get the value. Example:
|
||||
//
|
||||
// // The value will be output of Animal's String() func.
|
||||
// // Map will panic if Animal does not implement String().
|
||||
// Field *Animal `structs:"field,string"`
|
||||
//
|
||||
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
|
||||
// in the output map. Example:
|
||||
//
|
||||
// // The FieldStruct's fields will be flattened into the output map.
|
||||
// FieldStruct time.Time `structs:",flatten"`
|
||||
//
|
||||
// A tag value with the option of "omitnested" stops iterating further if the type
|
||||
// is a struct. Example:
|
||||
//
|
||||
// // Field is not processed further by this package.
|
||||
// Field time.Time `structs:"myName,omitnested"`
|
||||
// Field *http.Request `structs:",omitnested"`
|
||||
//
|
||||
// A tag value with the option of "omitempty" ignores that particular field if
|
||||
// the field value is empty. Example:
|
||||
//
|
||||
// // Field appears in map as key "myName", but the field is
|
||||
// // skipped if empty.
|
||||
// Field string `structs:"myName,omitempty"`
|
||||
//
|
||||
// // Field appears in map as key "Field" (the default), but
|
||||
// // the field is skipped if empty.
|
||||
// Field string `structs:",omitempty"`
|
||||
//
|
||||
// Note that only exported fields of a struct can be accessed, non exported
|
||||
// fields will be neglected.
|
||||
func (s *Struct) Map() map[string]interface{} {
|
||||
out := make(map[string]interface{})
|
||||
s.FillMap(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// FillMap is the same as Map. Instead of returning the output, it fills the
|
||||
// given map.
|
||||
func (s *Struct) FillMap(out map[string]interface{}) {
|
||||
if out == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fields := s.structFields()
|
||||
|
||||
for _, field := range fields {
|
||||
name := field.Name
|
||||
val := s.value.FieldByName(name)
|
||||
isSubStruct := false
|
||||
var finalVal interface{}
|
||||
|
||||
tagName, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||
if tagName != "" {
|
||||
name = tagName
|
||||
}
|
||||
|
||||
// if the value is a zero value and the field is marked as omitempty do
|
||||
// not include
|
||||
if tagOpts.Has("omitempty") {
|
||||
zero := reflect.Zero(val.Type()).Interface()
|
||||
current := val.Interface()
|
||||
|
||||
if reflect.DeepEqual(current, zero) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if !tagOpts.Has("omitnested") {
|
||||
finalVal = s.nested(val)
|
||||
|
||||
v := reflect.ValueOf(val.Interface())
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Map, reflect.Struct:
|
||||
isSubStruct = true
|
||||
}
|
||||
} else {
|
||||
finalVal = val.Interface()
|
||||
}
|
||||
|
||||
if tagOpts.Has("string") {
|
||||
s, ok := val.Interface().(fmt.Stringer)
|
||||
if ok {
|
||||
out[name] = s.String()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if isSubStruct && (tagOpts.Has("flatten")) {
|
||||
for k := range finalVal.(map[string]interface{}) {
|
||||
out[k] = finalVal.(map[string]interface{})[k]
|
||||
}
|
||||
} else {
|
||||
out[name] = finalVal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Values converts the given s struct's field values to a []interface{}. A
|
||||
// struct tag with the content of "-" ignores the that particular field.
|
||||
// Example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field int `structs:"-"`
|
||||
//
|
||||
// A value with the option of "omitnested" stops iterating further if the type
|
||||
// is a struct. Example:
|
||||
//
|
||||
// // Fields is not processed further by this package.
|
||||
// Field time.Time `structs:",omitnested"`
|
||||
// Field *http.Request `structs:",omitnested"`
|
||||
//
|
||||
// A tag value with the option of "omitempty" ignores that particular field and
|
||||
// is not added to the values if the field value is empty. Example:
|
||||
//
|
||||
// // Field is skipped if empty
|
||||
// Field string `structs:",omitempty"`
|
||||
//
|
||||
// Note that only exported fields of a struct can be accessed, non exported
|
||||
// fields will be neglected.
|
||||
func (s *Struct) Values() []interface{} {
|
||||
fields := s.structFields()
|
||||
|
||||
var t []interface{}
|
||||
|
||||
for _, field := range fields {
|
||||
val := s.value.FieldByName(field.Name)
|
||||
|
||||
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||
|
||||
// if the value is a zero value and the field is marked as omitempty do
|
||||
// not include
|
||||
if tagOpts.Has("omitempty") {
|
||||
zero := reflect.Zero(val.Type()).Interface()
|
||||
current := val.Interface()
|
||||
|
||||
if reflect.DeepEqual(current, zero) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if tagOpts.Has("string") {
|
||||
s, ok := val.Interface().(fmt.Stringer)
|
||||
if ok {
|
||||
t = append(t, s.String())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||
// look out for embedded structs, and convert them to a
|
||||
// []interface{} to be added to the final values slice
|
||||
t = append(t, Values(val.Interface())...)
|
||||
} else {
|
||||
t = append(t, val.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// Fields returns a slice of Fields. A struct tag with the content of "-"
|
||||
// ignores the checking of that particular field. Example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field bool `structs:"-"`
|
||||
//
|
||||
// It panics if s's kind is not struct.
|
||||
func (s *Struct) Fields() []*Field {
|
||||
return getFields(s.value, s.TagName)
|
||||
}
|
||||
|
||||
// Names returns a slice of field names. A struct tag with the content of "-"
|
||||
// ignores the checking of that particular field. Example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field bool `structs:"-"`
|
||||
//
|
||||
// It panics if s's kind is not struct.
|
||||
func (s *Struct) Names() []string {
|
||||
fields := getFields(s.value, s.TagName)
|
||||
|
||||
names := make([]string, len(fields))
|
||||
|
||||
for i, field := range fields {
|
||||
names[i] = field.Name()
|
||||
}
|
||||
|
||||
return names
|
||||
}
|
||||
|
||||
func getFields(v reflect.Value, tagName string) []*Field {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
|
||||
var fields []*Field
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
|
||||
if tag := field.Tag.Get(tagName); tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
f := &Field{
|
||||
field: field,
|
||||
value: v.FieldByName(field.Name),
|
||||
}
|
||||
|
||||
fields = append(fields, f)
|
||||
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// Field returns a new Field struct that provides several high level functions
|
||||
// around a single struct field entity. It panics if the field is not found.
|
||||
func (s *Struct) Field(name string) *Field {
|
||||
f, ok := s.FieldOk(name)
|
||||
if !ok {
|
||||
panic("field not found")
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// FieldOk returns a new Field struct that provides several high level functions
|
||||
// around a single struct field entity. The boolean returns true if the field
|
||||
// was found.
|
||||
func (s *Struct) FieldOk(name string) (*Field, bool) {
|
||||
t := s.value.Type()
|
||||
|
||||
field, ok := t.FieldByName(name)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &Field{
|
||||
field: field,
|
||||
value: s.value.FieldByName(name),
|
||||
defaultTag: s.TagName,
|
||||
}, true
|
||||
}
|
||||
|
||||
// IsZero returns true if all fields in a struct is a zero value (not
|
||||
// initialized) A struct tag with the content of "-" ignores the checking of
|
||||
// that particular field. Example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field bool `structs:"-"`
|
||||
//
|
||||
// A value with the option of "omitnested" stops iterating further if the type
|
||||
// is a struct. Example:
|
||||
//
|
||||
// // Field is not processed further by this package.
|
||||
// Field time.Time `structs:"myName,omitnested"`
|
||||
// Field *http.Request `structs:",omitnested"`
|
||||
//
|
||||
// Note that only exported fields of a struct can be accessed, non exported
|
||||
// fields will be neglected. It panics if s's kind is not struct.
|
||||
func (s *Struct) IsZero() bool {
|
||||
fields := s.structFields()
|
||||
|
||||
for _, field := range fields {
|
||||
val := s.value.FieldByName(field.Name)
|
||||
|
||||
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||
|
||||
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||
ok := IsZero(val.Interface())
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// zero value of the given field, such as "" for string, 0 for int
|
||||
zero := reflect.Zero(val.Type()).Interface()
|
||||
|
||||
// current value of the given field
|
||||
current := val.Interface()
|
||||
|
||||
if !reflect.DeepEqual(current, zero) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// HasZero returns true if a field in a struct is not initialized (zero value).
|
||||
// A struct tag with the content of "-" ignores the checking of that particular
|
||||
// field. Example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field bool `structs:"-"`
|
||||
//
|
||||
// A value with the option of "omitnested" stops iterating further if the type
|
||||
// is a struct. Example:
|
||||
//
|
||||
// // Field is not processed further by this package.
|
||||
// Field time.Time `structs:"myName,omitnested"`
|
||||
// Field *http.Request `structs:",omitnested"`
|
||||
//
|
||||
// Note that only exported fields of a struct can be accessed, non exported
|
||||
// fields will be neglected. It panics if s's kind is not struct.
|
||||
func (s *Struct) HasZero() bool {
|
||||
fields := s.structFields()
|
||||
|
||||
for _, field := range fields {
|
||||
val := s.value.FieldByName(field.Name)
|
||||
|
||||
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||
|
||||
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||
ok := HasZero(val.Interface())
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// zero value of the given field, such as "" for string, 0 for int
|
||||
zero := reflect.Zero(val.Type()).Interface()
|
||||
|
||||
// current value of the given field
|
||||
current := val.Interface()
|
||||
|
||||
if reflect.DeepEqual(current, zero) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Name returns the structs's type name within its package. For more info refer
|
||||
// to Name() function.
|
||||
func (s *Struct) Name() string {
|
||||
return s.value.Type().Name()
|
||||
}
|
||||
|
||||
// structFields returns the exported struct fields for a given s struct. This
|
||||
// is a convenient helper method to avoid duplicate code in some of the
|
||||
// functions.
|
||||
func (s *Struct) structFields() []reflect.StructField {
|
||||
t := s.value.Type()
|
||||
|
||||
var f []reflect.StructField
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
// we can't access the value of unexported fields
|
||||
if field.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// don't check if it's omitted
|
||||
if tag := field.Tag.Get(s.TagName); tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
f = append(f, field)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func strctVal(s interface{}) reflect.Value {
|
||||
v := reflect.ValueOf(s)
|
||||
|
||||
// if pointer get the underlying element≤
|
||||
for v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Struct {
|
||||
panic("not struct")
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Map converts the given struct to a map[string]interface{}. For more info
|
||||
// refer to Struct types Map() method. It panics if s's kind is not struct.
|
||||
func Map(s interface{}) map[string]interface{} {
|
||||
return New(s).Map()
|
||||
}
|
||||
|
||||
// FillMap is the same as Map. Instead of returning the output, it fills the
|
||||
// given map.
|
||||
func FillMap(s interface{}, out map[string]interface{}) {
|
||||
New(s).FillMap(out)
|
||||
}
|
||||
|
||||
// Values converts the given struct to a []interface{}. For more info refer to
|
||||
// Struct types Values() method. It panics if s's kind is not struct.
|
||||
func Values(s interface{}) []interface{} {
|
||||
return New(s).Values()
|
||||
}
|
||||
|
||||
// Fields returns a slice of *Field. For more info refer to Struct types
|
||||
// Fields() method. It panics if s's kind is not struct.
|
||||
func Fields(s interface{}) []*Field {
|
||||
return New(s).Fields()
|
||||
}
|
||||
|
||||
// Names returns a slice of field names. For more info refer to Struct types
|
||||
// Names() method. It panics if s's kind is not struct.
|
||||
func Names(s interface{}) []string {
|
||||
return New(s).Names()
|
||||
}
|
||||
|
||||
// IsZero returns true if all fields is equal to a zero value. For more info
|
||||
// refer to Struct types IsZero() method. It panics if s's kind is not struct.
|
||||
func IsZero(s interface{}) bool {
|
||||
return New(s).IsZero()
|
||||
}
|
||||
|
||||
// HasZero returns true if any field is equal to a zero value. For more info
|
||||
// refer to Struct types HasZero() method. It panics if s's kind is not struct.
|
||||
func HasZero(s interface{}) bool {
|
||||
return New(s).HasZero()
|
||||
}
|
||||
|
||||
// IsStruct returns true if the given variable is a struct or a pointer to
|
||||
// struct.
|
||||
func IsStruct(s interface{}) bool {
|
||||
v := reflect.ValueOf(s)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
// uninitialized zero value of a struct
|
||||
if v.Kind() == reflect.Invalid {
|
||||
return false
|
||||
}
|
||||
|
||||
return v.Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
// Name returns the structs's type name within its package. It returns an
|
||||
// empty string for unnamed types. It panics if s's kind is not struct.
|
||||
func Name(s interface{}) string {
|
||||
return New(s).Name()
|
||||
}
|
||||
|
||||
// nested retrieves recursively all types for the given value and returns the
|
||||
// nested value.
|
||||
func (s *Struct) nested(val reflect.Value) interface{} {
|
||||
var finalVal interface{}
|
||||
|
||||
v := reflect.ValueOf(val.Interface())
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
n := New(val.Interface())
|
||||
n.TagName = s.TagName
|
||||
m := n.Map()
|
||||
|
||||
// do not add the converted value if there are no exported fields, ie:
|
||||
// time.Time
|
||||
if len(m) == 0 {
|
||||
finalVal = val.Interface()
|
||||
} else {
|
||||
finalVal = m
|
||||
}
|
||||
case reflect.Map:
|
||||
// get the element type of the map
|
||||
mapElem := val.Type()
|
||||
switch val.Type().Kind() {
|
||||
case reflect.Ptr, reflect.Array, reflect.Map,
|
||||
reflect.Slice, reflect.Chan:
|
||||
mapElem = val.Type().Elem()
|
||||
if mapElem.Kind() == reflect.Ptr {
|
||||
mapElem = mapElem.Elem()
|
||||
}
|
||||
}
|
||||
|
||||
// only iterate over struct types, ie: map[string]StructType,
|
||||
// map[string][]StructType,
|
||||
if mapElem.Kind() == reflect.Struct ||
|
||||
(mapElem.Kind() == reflect.Slice &&
|
||||
mapElem.Elem().Kind() == reflect.Struct) {
|
||||
m := make(map[string]interface{}, val.Len())
|
||||
for _, k := range val.MapKeys() {
|
||||
m[k.String()] = s.nested(val.MapIndex(k))
|
||||
}
|
||||
finalVal = m
|
||||
break
|
||||
}
|
||||
|
||||
// TODO(arslan): should this be optional?
|
||||
finalVal = val.Interface()
|
||||
case reflect.Slice, reflect.Array:
|
||||
if val.Type().Kind() == reflect.Interface {
|
||||
finalVal = val.Interface()
|
||||
break
|
||||
}
|
||||
|
||||
// TODO(arslan): should this be optional?
|
||||
// do not iterate of non struct types, just pass the value. Ie: []int,
|
||||
// []string, co... We only iterate further if it's a struct.
|
||||
// i.e []foo or []*foo
|
||||
if val.Type().Elem().Kind() != reflect.Struct &&
|
||||
!(val.Type().Elem().Kind() == reflect.Ptr &&
|
||||
val.Type().Elem().Elem().Kind() == reflect.Struct) {
|
||||
finalVal = val.Interface()
|
||||
break
|
||||
}
|
||||
|
||||
slices := make([]interface{}, val.Len())
|
||||
for x := 0; x < val.Len(); x++ {
|
||||
slices[x] = s.nested(val.Index(x))
|
||||
}
|
||||
finalVal = slices
|
||||
default:
|
||||
finalVal = val.Interface()
|
||||
}
|
||||
|
||||
return finalVal
|
||||
}
|
33
iSolarCloud/api/apiReflect/tags.go
Normal file
@ -0,0 +1,33 @@
|
||||
// Package apiReflect - Snaffooed from https://github.com/fatih/structs
|
||||
package apiReflect
|
||||
|
||||
import "strings"
|
||||
|
||||
// tagOptions contains a slice of tag options
|
||||
type tagOptions []string
|
||||
|
||||
// Has returns true if the given option is available in tagOptions
|
||||
func (t tagOptions) Has(opt string) bool {
|
||||
for _, tagOpt := range t {
|
||||
if tagOpt == opt {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// parseTag splits a struct field's tag into its name and a list of options
|
||||
// which comes after a name. A tag is in the form of: "name,option1,option2".
|
||||
// The name can be neglectected.
|
||||
func parseTag(tag string) (string, tagOptions) {
|
||||
// tag is one of followings:
|
||||
// ""
|
||||
// "name"
|
||||
// "name,opt"
|
||||
// "name,opt,opt2"
|
||||
// ",opt"
|
||||
|
||||
res := strings.Split(tag, ",")
|
||||
return res[0], res[1:]
|
||||
}
|
@ -49,6 +49,10 @@ func NewDateTime(date string) DateTime {
|
||||
return ret
|
||||
}
|
||||
|
||||
func TimeNowString() string {
|
||||
return time.Now().Format(DtLayout)
|
||||
}
|
||||
|
||||
func (dt *DateTime) GetDayStartTimestamp() string {
|
||||
var ret string
|
||||
f1 := dt.Time.Round(time.Hour * 24)
|
||||
|
374
iSolarCloud/api/struct_points.go
Normal file
@ -0,0 +1,374 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
const (
|
||||
PointTypeInstant = "instant"
|
||||
PointTypeDaily = "daily"
|
||||
PointTypeMonthly = "monthly"
|
||||
PointTypeYearly = "yearly"
|
||||
PointTypeTotal = "total"
|
||||
)
|
||||
|
||||
|
||||
type Point struct {
|
||||
PsKey string
|
||||
Id string
|
||||
Description string
|
||||
Unit string
|
||||
Type string
|
||||
}
|
||||
type PointsMap map[string]Point
|
||||
|
||||
|
||||
func (pm *PointsMap) Resolve(point string) *Point {
|
||||
if ret, ok := (*pm)[point]; ok {
|
||||
return &ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ResolvePoint(point string) *Point {
|
||||
return Points.Resolve(point)
|
||||
}
|
||||
|
||||
// p1
|
||||
// p1001
|
||||
// p1002
|
||||
// p1005
|
||||
// p1302
|
||||
// p14
|
||||
// p2
|
||||
// p202
|
||||
// p210
|
||||
// p24
|
||||
// p24001
|
||||
// p24004
|
||||
// p66
|
||||
// p8018
|
||||
// p8030
|
||||
// p8031
|
||||
// p8062
|
||||
// p8063
|
||||
// p81002
|
||||
// p81022
|
||||
// p81023
|
||||
// p81202
|
||||
// p81203
|
||||
// p83011
|
||||
// p83012
|
||||
// p83039
|
||||
// p83046
|
||||
// p83048
|
||||
// p83049
|
||||
// p83050
|
||||
// p83051
|
||||
// p83054
|
||||
// p83055
|
||||
// p83067
|
||||
// p83070
|
||||
// p83072
|
||||
// p83075
|
||||
// p83076
|
||||
// p83077
|
||||
// p83080
|
||||
// p83081
|
||||
// p83086
|
||||
// p83087
|
||||
// p83088
|
||||
// p83089
|
||||
// p83095
|
||||
// p83096
|
||||
// p83101
|
||||
// p83118
|
||||
// p83119
|
||||
// p83120
|
||||
// p83121
|
||||
// p83122
|
||||
// p83127
|
||||
// p83202
|
||||
// p83532
|
||||
|
||||
// Points Discovered points from the API
|
||||
var Points = PointsMap {
|
||||
|
||||
"p13001": { PsKey: "1129147_14_1_1", Id: "p13001", Description: "MPPT1 Voltage", Unit: "V", Type: PointTypeInstant },
|
||||
|
||||
"p13012": { PsKey: "1129147_14_1_1", Id: "p13012", Description: "Total Reactive Power", Unit: "kvar", Type: PointTypeDaily },
|
||||
|
||||
"p13105": { PsKey: "1129147_14_1_1", Id: "p13105", Description: "MPPT2 Voltage", Unit: "V", Type: PointTypeInstant },
|
||||
|
||||
"p13122": { PsKey: "1129147_14_1_1", Id: "p13122", Description: "Daily Feed-in Energy", Unit: "kWh", Type: PointTypeDaily },
|
||||
|
||||
"p13125": { PsKey: "1129147_14_1_1", Id: "p13125", Description: "Total Feed-in Energy", Unit: "kWh", Type: PointTypeTotal },
|
||||
|
||||
"p13138": { PsKey: "1129147_14_1_1", Id: "p13138", Description: "Battery Voltage", Unit: "V", Type: PointTypeInstant },
|
||||
|
||||
"p13144": { PsKey: "1129147_14_1_1", Id: "p13144", Description: "Daily Self-consumption Rate", Unit: "%", Type: PointTypeDaily },
|
||||
|
||||
"p13157": { PsKey: "1129147_14_1_1", Id: "p13157", Description: "Phase A Voltage", Unit: "V", Type: PointTypeInstant },
|
||||
|
||||
"p13158": { PsKey: "1129147_14_1_1", Id: "p13158", Description: "Phase B Voltage", Unit: "V", Type: PointTypeInstant },
|
||||
|
||||
"p13159": { PsKey: "1129147_14_1_1", Id: "p13159", Description: "Phase C Voltage", Unit: "V", Type: PointTypeInstant },
|
||||
|
||||
"p13161": { PsKey: "1129147_14_1_1", Id: "p13161", Description: "Bus Voltage", Unit: "V", Type: PointTypeInstant },
|
||||
"p13173": { PsKey: "1129147_14_1_1", Id: "p13173", Description: "Daily Feed-in Energy (PV)", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p13175": { PsKey: "1129147_14_1_1", Id: "p13175", Description: "Total Feed-in Energy (PV)", Unit: "kWh", Type: PointTypeTotal },
|
||||
"p13002": { PsKey: "1129147_14_1_1", Id: "p13002", Description: "MPPT1 Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p13003": { PsKey: "1129147_14_1_1", Id: "p13003", Description: "Total DC Power", Unit: "kW" },
|
||||
"p13007": { PsKey: "1129147_14_1_1", Id: "p13007", Description: "Grid Frequency", Unit: "Hz", Type: PointTypeInstant },
|
||||
"p13008": { PsKey: "1129147_14_1_1", Id: "p13008", Description: "Phase A Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p13009": { PsKey: "1129147_14_1_1", Id: "p13009", Description: "Phase B Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p13010": { PsKey: "1129147_14_1_1", Id: "p13010", Description: "Phase C Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p13011": { PsKey: "1129147_14_1_1", Id: "p13011", Description: "Total Active Power", Unit: "kW" },
|
||||
"p13013": { PsKey: "1129147_14_1_1", Id: "p13013", Description: "Total Power Factor", Unit: "" },
|
||||
"p13018": { PsKey: "1129147_14_1_1", Id: "p13018", Description: "Total Apparent Power", Unit: "VA" },
|
||||
"p13019": { PsKey: "1129147_14_1_1", Id: "p13019", Description: "Internal Air Temperature", Unit: "℃", Type: PointTypeInstant },
|
||||
"p13028": { PsKey: "1129147_14_1_1", Id: "p13028", Description: "Daily Battery Charging Energy", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p13029": { PsKey: "1129147_14_1_1", Id: "p13029", Description: "Daily Battery Discharging Energy", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p13034": { PsKey: "1129147_14_1_1", Id: "p13034", Description: "Total Battery Charging Energy", Unit: "kWh" , Type: PointTypeTotal },
|
||||
"p13035": { PsKey: "1129147_14_1_1", Id: "p13035", Description: "Total Battery Discharging Energy", Unit: "kWh" , Type: PointTypeTotal },
|
||||
"p13106": { PsKey: "1129147_14_1_1", Id: "p13106", Description: "MPPT2 Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p13112": { PsKey: "1129147_14_1_1", Id: "p13112", Description: "Daily PV Yield", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p13116": { PsKey: "1129147_14_1_1", Id: "p13116", Description: "Daily Load Energy Consumption from PV", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p13119": { PsKey: "1129147_14_1_1", Id: "p13119", Description: "Total Load Active Power", Unit: "kW" },
|
||||
"p13121": { PsKey: "1129147_14_1_1", Id: "p13121", Description: "Total Export Active Power", Unit: "kW" },
|
||||
"p13126": { PsKey: "1129147_14_1_1", Id: "p13126", Description: "Battery Charging Power", Unit: "kW" },
|
||||
"p13130": { PsKey: "1129147_14_1_1", Id: "p13130", Description: "Total Load Energy Consumption", Unit: "kWh" , Type: PointTypeTotal },
|
||||
"p13134": { PsKey: "1129147_14_1_1", Id: "p13134", Description: "Total PV Yield", Unit: "kWh" , Type: PointTypeTotal },
|
||||
"p13137": { PsKey: "1129147_14_1_1", Id: "p13137", Description: "Total Load Energy Consumption from PV", Unit: "kWh" , Type: PointTypeTotal },
|
||||
"p13139": { PsKey: "1129147_14_1_1", Id: "p13139", Description: "Battery Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p13140": { PsKey: "1129147_14_1_1", Id: "p13140", Description: "Battery Capacity(kWh)", Unit: "kWh" },
|
||||
"p13141": { PsKey: "1129147_14_1_1", Id: "p13141", Description: "Battery Level (SOC)", Unit: "%", Type: PointTypeInstant },
|
||||
"p13142": { PsKey: "1129147_14_1_1", Id: "p13142", Description: "Battery Health (SOH)", Unit: "%", Type: PointTypeInstant },
|
||||
"p13143": { PsKey: "1129147_14_1_1", Id: "p13143", Description: "Battery Temperature", Unit: "℃", Type: PointTypeInstant },
|
||||
"p13147": { PsKey: "1129147_14_1_1", Id: "p13147", Description: "Daily Purchased Energy", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p13148": { PsKey: "1129147_14_1_1", Id: "p13148", Description: "Total Purchased Energy", Unit: "kWh", Type: PointTypeTotal },
|
||||
"p13149": { PsKey: "1129147_14_1_1", Id: "p13149", Description: "Purchased Power", Unit: "kW" },
|
||||
"p13150": { PsKey: "1129147_14_1_1", Id: "p13150", Description: "Battery Discharging Power", Unit: "kW" },
|
||||
"p13160": { PsKey: "1129147_14_1_1", Id: "p13160", Description: "Array Insulation Resistance", Unit: "kΩ", Type: PointTypeInstant },
|
||||
"p13162": { PsKey: "1129147_14_1_1", Id: "p13162", Description: "Max. Charging Current (BMS)", Unit: "A", Type: PointTypeInstant },
|
||||
"p13163": { PsKey: "1129147_14_1_1", Id: "p13163", Description: "Max. Discharging Current (BMS)", Unit: "A", Type: PointTypeInstant },
|
||||
"p13174": { PsKey: "1129147_14_1_1", Id: "p13174", Description: "Daily Battery Charging Energy from PV", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p13176": { PsKey: "1129147_14_1_1", Id: "p13176", Description: "Total Battery Charging Energy from PV", Unit: "kWh", Type: PointTypeTotal },
|
||||
"p13199": { PsKey: "1129147_14_1_1", Id: "p13199", Description: "Daily Load Energy Consumption", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p18062": { PsKey: "1129147_14_1_1", Id: "p18062", Description: "Phase A Backup Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p18063": { PsKey: "1129147_14_1_1", Id: "p18063", Description: "Phase B Backup Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p18064": { PsKey: "1129147_14_1_1", Id: "p18064", Description: "Phase C Backup Current", Unit: "A", Type: PointTypeInstant },
|
||||
"p18065": { PsKey: "1129147_14_1_1", Id: "p18065", Description: "Phase A Backup Power", Unit: "kW" },
|
||||
"p18066": { PsKey: "1129147_14_1_1", Id: "p18066", Description: "Phase B Backup Power", Unit: "kW" },
|
||||
"p18067": { PsKey: "1129147_14_1_1", Id: "p18067", Description: "Phase C Backup Power", Unit: "kW" },
|
||||
"p18068": { PsKey: "1129147_14_1_1", Id: "p18068", Description: "Total Backup Power", Unit: "kW" },
|
||||
"p83001": { PsKey: "1129147_11_0_0", Id: "p83001", Description: "Inverter AC Power Normalization", Unit: "kW/kWp" },
|
||||
"p83002": { PsKey: "1129147_11_0_0", Id: "p83002", Description: "Inverter AC Power", Unit: "kW" },
|
||||
"p83004": { PsKey: "1129147_11_0_0", Id: "p83004", Description: "Inverter Total Yield", Unit: "kWh" },
|
||||
"p83005": { PsKey: "1129147_11_0_0", Id: "p83005", Description: "Daily Equivalent Hours of Meter", Unit: "h", Type: PointTypeDaily },
|
||||
"p83006": { PsKey: "1129147_11_0_0", Id: "p83006", Description: "Meter Daily Yield", Unit: "kWh" },
|
||||
"p83007": { PsKey: "1129147_11_0_0", Id: "p83007", Description: "Meter PR", Unit: "%", Type: PointTypeInstant },
|
||||
"p83008": { PsKey: "1129147_11_0_0", Id: "p83008", Description: "Daily Equivalent Hours of Inverter", Unit: "h", Type: PointTypeDaily },
|
||||
"p83009": { PsKey: "1129147_11_0_0", Id: "p83009", Description: "Daily Yield by Inverter", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p83010": { PsKey: "1129147_11_0_0", Id: "p83010", Description: "Inverter PR", Unit: "%", Type: PointTypeInstant },
|
||||
"p83013": { PsKey: "1129147_11_0_0", Id: "p83013", Description: "Daily Irradiation", Unit: "Wh/m2" },
|
||||
"p83016": { PsKey: "1129147_11_0_0", Id: "p83016", Description: "Plant Ambient Temperature", Unit: "℃", Type: PointTypeInstant },
|
||||
"p83017": { PsKey: "1129147_11_0_0", Id: "p83017", Description: "Plant Module Temperature", Unit: "℃", Type: PointTypeInstant },
|
||||
"p83018": { PsKey: "1129147_11_0_0", Id: "p83018", Description: "Daily Yield (Theoretical)", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p83019": { PsKey: "1129147_11_0_0", Id: "p83019", Description: "Power/Installed Power of Plant", Unit: "%", Type: PointTypeInstant },
|
||||
"p83020": { PsKey: "1129147_11_0_0", Id: "p83020", Description: "Meter Total Yield", Unit: "kWh" },
|
||||
"p83021": { PsKey: "1129147_11_0_0", Id: "p83021", Description: "Accumulative Power Consumption by Meter", Unit: "kWh" },
|
||||
"p83022": { PsKey: "1129147_11_0_0", Id: "p83022", Description: "Daily Yield of Plant", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p83023": { PsKey: "1129147_11_0_0", Id: "p83023", Description: "Plant PR", Unit: "%", Type: PointTypeInstant },
|
||||
"p83024": { PsKey: "1129147_11_0_0", Id: "p83024", Description: "Plant Total Yield", Unit: "kWh" },
|
||||
"p83025": { PsKey: "1129147_11_0_0", Id: "p83025", Description: "Plant Equivalent Hours", Unit: "h" },
|
||||
"p83032": { PsKey: "1129147_11_0_0", Id: "p83032", Description: "Meter AC Power", Unit: "kW" },
|
||||
"p83033": { PsKey: "1129147_11_0_0", Id: "p83033", Description: "Plant Power", Unit: "kW" },
|
||||
"p83097": { PsKey: "1129147_11_0_0", Id: "p83097", Description: "Daily Load Energy Consumption from PV", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p83100": { PsKey: "1129147_11_0_0", Id: "p83100", Description: "Total Load Energy Consumption from PV", Unit: "kWh" },
|
||||
"p83102": { PsKey: "1129147_11_0_0", Id: "p83102", Description: "Daily Purchased Energy", Unit: "kWh", Type: PointTypeDaily },
|
||||
"p83105": { PsKey: "1129147_11_0_0", Id: "p83105", Description: "Total Purchased Energy", Unit: "kWh" },
|
||||
"p83106": { PsKey: "1129147_11_0_0", Id: "p83106", Description: "Load Power", Unit: "kW" },
|
||||
"p83124": { PsKey: "1129147_11_0_0", Id: "p83124", Description: "Total Load Energy Consumption", Unit: "MWh" },
|
||||
"p83128": { PsKey: "1129147_11_0_0", Id: "p83128", Description: "Total Active Power of Optical Storage", Unit: "kW" },
|
||||
"p83129": { PsKey: "1129147_11_0_0", Id: "p83129", Description: "Battery SOC", Unit: "%", Type: PointTypeInstant },
|
||||
"p83233": { PsKey: "1129147_11_0_0", Id: "p83233", Description: "Total field maximum rechargeable power", Unit: "MW" },
|
||||
"p83234": { PsKey: "1129147_11_0_0", Id: "p83234", Description: "Total field maximum dischargeable power", Unit: "MW" },
|
||||
"p83235": { PsKey: "1129147_11_0_0", Id: "p83235", Description: "Total field chargeable energy", Unit: "MWh" },
|
||||
"p83236": { PsKey: "1129147_11_0_0", Id: "p83236", Description: "Total field dischargeable energy", Unit: "MWh" },
|
||||
"p83237": { PsKey: "1129147_11_0_0", Id: "p83237", Description: "Total field energy storage maximum reactive power", Unit: "MW" },
|
||||
"p83238": { PsKey: "1129147_11_0_0", Id: "p83238", Description: "Total field energy storage active power", Unit: "MW" },
|
||||
"p83239": { PsKey: "1129147_11_0_0", Id: "p83239", Description: "Total field reactive power", Unit: "Mvar" },
|
||||
"p83241": { PsKey: "1129147_11_0_0", Id: "p83241", Description: "Total field charge capacity", Unit: "MWh" },
|
||||
"p83242": { PsKey: "1129147_11_0_0", Id: "p83242", Description: "Total field discharge capacity", Unit: "MWh" },
|
||||
"p83243": { PsKey: "1129147_11_0_0", Id: "p83243", Description: "Total field daily charge capacity", Unit: "MWh" },
|
||||
"p83244": { PsKey: "1129147_11_0_0", Id: "p83244", Description: "Total field daily discharge capacity", Unit: "MWh" },
|
||||
"p83252": { PsKey: "1129147_11_0_0", Id: "p83252", Description: "Battery Level (SOC)", Unit: "%", Type: PointTypeInstant },
|
||||
"p83419": { PsKey: "1129147_11_0_0", Id: "p83419", Description: "Daily Highest Inverter Power/Inverter Installed Capacity", Unit: "%" },
|
||||
"p83420": { PsKey: "1129147_11_0_0", Id: "p83420", Description: "Current Power/Inverter Installed Capacity", Unit: "%", Type: PointTypeInstant },
|
||||
"p83549": { PsKey: "1129147_11_0_0", Id: "p83549", Description: "Grid active power", Unit: "kW" },
|
||||
|
||||
"p23014": { PsKey: "1129147_22_247_1", Id: "p23014", Description: "WLAN Signal Strength", Unit: "" },
|
||||
|
||||
}
|
||||
|
||||
|
||||
func GetPoint(device string, point string) *Point {
|
||||
return Points.Get(device, point)
|
||||
}
|
||||
|
||||
func GetPointInt(device string, point int64) *Point {
|
||||
return Points.Get(device, strconv.FormatInt(point, 10))
|
||||
}
|
||||
|
||||
func GetDevicePoint(devicePoint string) *Point {
|
||||
return Points.GetDevicePoint(devicePoint)
|
||||
}
|
||||
|
||||
// func GetPointName(device string, point int64) string {
|
||||
// return fmt.Sprintf("%s.%d", device, point)
|
||||
// }
|
||||
|
||||
func NameDevicePointInt(device string, point int64) string {
|
||||
return fmt.Sprintf("%s.%d", device, point)
|
||||
}
|
||||
|
||||
func NameDevicePoint(device string, point string) string {
|
||||
return fmt.Sprintf("%s.%s", device, point)
|
||||
}
|
||||
|
||||
func (p *Point) WhenReset() string {
|
||||
var ret string
|
||||
|
||||
for range Only.Once {
|
||||
var err error
|
||||
now := time.Now()
|
||||
|
||||
switch {
|
||||
case p.IsInstant():
|
||||
ret = ""
|
||||
|
||||
case p.IsDaily():
|
||||
now, err = time.Parse("2006-01-02T15:04:05", now.Format("2006-01-02") + "T00:00:00")
|
||||
// ret = fmt.Sprintf("%d", now.Unix())
|
||||
ret = now.Format("2006-01-02T15:04:05") + ""
|
||||
|
||||
case p.IsMonthly():
|
||||
now, err = time.Parse("2006-01-02T15:04:05", now.Format("2006-01") + "-01T00:00:00")
|
||||
ret = fmt.Sprintf("%d", now.Unix())
|
||||
ret = now.Format("2006-01-02T15:04:05") + ""
|
||||
|
||||
case p.IsYearly():
|
||||
now, err = time.Parse("2006-01-02T15:04:05", now.Format("2006") + "-01-01T00:00:00")
|
||||
ret = fmt.Sprintf("%d", now.Unix())
|
||||
ret = now.Format("2006-01-02T15:04:05") + ""
|
||||
|
||||
case p.IsTotal():
|
||||
// ret = "0"
|
||||
ret = "1970-01-01T00:00:00"
|
||||
|
||||
default:
|
||||
// ret = "0"
|
||||
ret = "1970-01-01T00:00:00"
|
||||
}
|
||||
if err != nil {
|
||||
now := time.Now()
|
||||
ret = fmt.Sprintf("%d", now.Unix())
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p Point) String() string {
|
||||
return p.Type
|
||||
}
|
||||
|
||||
func (pm PointsMap) Get(device string, point string) *Point {
|
||||
dp := device + ".p" + strings.TrimPrefix(point, "p")
|
||||
if p, ok := pm[dp]; ok {
|
||||
return &p
|
||||
}
|
||||
|
||||
dp = "p" + strings.TrimPrefix(point, "p")
|
||||
if p, ok := pm[dp]; ok {
|
||||
return &p
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pm PointsMap) GetDevicePoint(devicePoint string) *Point {
|
||||
ret := &Point{}
|
||||
for range Only.Once {
|
||||
s := strings.Split(devicePoint, ".")
|
||||
if len(s) < 2 {
|
||||
break
|
||||
}
|
||||
ret = pm.Get(s[0], s[1])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p Point) IsInstant() bool {
|
||||
if p.Type == PointTypeInstant {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Point) IsDaily() bool {
|
||||
if p.Type == PointTypeDaily {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Point) IsMonthly() bool {
|
||||
if p.Type == PointTypeMonthly {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Point) IsYearly() bool {
|
||||
if p.Type == PointTypeYearly {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Point) IsTotal() bool {
|
||||
if p.Type == PointTypeTotal {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
func UpperCase(s string) string {
|
||||
s = strings.ReplaceAll(s, "_", " ")
|
||||
s = strings.Title(s)
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
type Data struct {
|
||||
Entries []DataEntry
|
||||
}
|
||||
|
||||
type DataEntry struct {
|
||||
Date DateTime `json:"date"`
|
||||
PointId string `json:"point_id"`
|
||||
PointGroupName string `json:"point_group_name"`
|
||||
PointName string `json:"point_name"`
|
||||
Value string `json:"value"`
|
||||
Unit string `json:"unit"`
|
||||
ValueType *Point `json:"value_type"`
|
||||
Index int `json:"index"`
|
||||
}
|
@ -48,17 +48,21 @@ func (req ResponseCommon) IsTokenValid() bool {
|
||||
var ok bool
|
||||
for range Only.Once {
|
||||
switch {
|
||||
case req.ResultMsg == "success":
|
||||
ok = true
|
||||
case req.ResultMsg == "er_token_login_invalid":
|
||||
ok = false
|
||||
default:
|
||||
ok = false
|
||||
case req.ResultMsg == "success":
|
||||
ok = true
|
||||
case req.ResultMsg == "er_token_login_invalid":
|
||||
ok = false
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
func (req ResponseCommon) IsTokenInvalid() bool {
|
||||
return !req.IsTokenValid()
|
||||
}
|
||||
|
||||
func (req ResponseCommon) String() string {
|
||||
var ret string
|
||||
ret = fmt.Sprintf("ReqSerialNum:\t%s\n", req.ReqSerialNum)
|
||||
|
@ -1,6 +1,74 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
type UnitValue struct {
|
||||
Unit string `json:"unit"`
|
||||
Value string `json:"value"`
|
||||
Point *Point `json:"point"`
|
||||
}
|
||||
type UnitValues []UnitValue
|
||||
type UnitValueMap map[string]UnitValue
|
||||
|
||||
|
||||
|
||||
func (u *UnitValueMap) Sort() []string {
|
||||
var ret []string
|
||||
for n := range *u {
|
||||
ret = append(ret, n)
|
||||
}
|
||||
sort.Strings(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
func JsonToUnitValue(j string) UnitValue {
|
||||
var ret UnitValue
|
||||
|
||||
for range Only.Once {
|
||||
err := json.Unmarshal([]byte(j), &ret)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func Float32ToString(num float64) string {
|
||||
s := fmt.Sprintf("%.6f", num)
|
||||
return strings.TrimRight(strings.TrimRight(s, "0"), ".")
|
||||
}
|
||||
|
||||
func Float64ToString(num float64) string {
|
||||
s := fmt.Sprintf("%.6f", num)
|
||||
return strings.TrimRight(strings.TrimRight(s, "0"), ".")
|
||||
}
|
||||
|
||||
func DivideByThousand(num string) (string, error) {
|
||||
fv, err := strconv.ParseFloat(num, 64)
|
||||
if err == nil {
|
||||
num = Float64ToString(fv / 1000)
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
// func (u *UnitValue) GetStructName() string {
|
||||
// var ret string
|
||||
// apiReflect.GetName()
|
||||
// return ret
|
||||
// }
|
||||
//
|
||||
// func (u *UnitValue) GetJsonName() string {
|
||||
// var ret string
|
||||
// apiReflect.GetOptionsRequired()
|
||||
// return ret
|
||||
// }
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -55,3 +56,40 @@ func GetUrl(u string) *url.URL {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetStructKeys(ref interface{}, keys ...string) UnitValueMap {
|
||||
ret := make(UnitValueMap)
|
||||
|
||||
for _, k := range apiReflect.GetStructKeys(ref, keys...) {
|
||||
p := UnitValue { Value: k.Value, Unit: "" }
|
||||
if k.Type.Name() == "UnitValue" {
|
||||
// v = JsonToUnitValue(k.JsonValue).Value
|
||||
// u = JsonToUnitValue(k.JsonValue).Unit
|
||||
p = JsonToUnitValue(k.JsonValue)
|
||||
|
||||
p.Value, p.Unit = DivideByThousandIfRequired(p.Value, p.Unit)
|
||||
}
|
||||
|
||||
k.JsonName = strings.TrimSuffix(k.JsonName, "_map") // Bit of a hack, but hey... @TODO - Future self take note.
|
||||
ret[k.JsonName] = p
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// DivideByThousandIfRequired Sigh.... Another dodgy one.
|
||||
func DivideByThousandIfRequired(value string, unit string) (string, string) {
|
||||
switch unit {
|
||||
case "Wh":
|
||||
fallthrough
|
||||
case "W":
|
||||
fv, err := strconv.ParseFloat(value, 64)
|
||||
if err == nil {
|
||||
fv = fv / 1000
|
||||
value, _ = DivideByThousand(value)
|
||||
unit = "k" + unit
|
||||
}
|
||||
}
|
||||
|
||||
return value, unit
|
||||
}
|
||||
|
@ -2,12 +2,14 @@ package iSolarCloud
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/iSolarCloud/AppService/getPsDetailWithPsType"
|
||||
"GoSungrow/iSolarCloud/AppService/getPsList"
|
||||
"GoSungrow/iSolarCloud/AppService/queryMutiPointDataList"
|
||||
"GoSungrow/iSolarCloud/api"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -142,7 +144,7 @@ func (sg *SunGrow) GetPointData(date string, pointNames api.TemplatePoints) erro
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep2, table, "")
|
||||
sg.Error = sg.Output(ep2, &table, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
@ -151,15 +153,21 @@ func (sg *SunGrow) GetPointData(date string, pointNames api.TemplatePoints) erro
|
||||
return sg.Error
|
||||
}
|
||||
|
||||
func (sg *SunGrow) Output(endpoint api.EndPoint, table output.Table, graphFilter string) error {
|
||||
func (sg *SunGrow) Output(endpoint api.EndPoint, table *output.Table, graphFilter string) error {
|
||||
for range Only.Once {
|
||||
switch {
|
||||
case sg.OutputType.IsNone():
|
||||
|
||||
case sg.OutputType.IsHuman():
|
||||
if table == nil {
|
||||
break
|
||||
}
|
||||
table.Print()
|
||||
|
||||
case sg.OutputType.IsFile():
|
||||
if table == nil {
|
||||
break
|
||||
}
|
||||
sg.Error = table.WriteCsvFile()
|
||||
|
||||
case sg.OutputType.IsRaw():
|
||||
@ -169,6 +177,9 @@ func (sg *SunGrow) Output(endpoint api.EndPoint, table output.Table, graphFilter
|
||||
fmt.Println(endpoint.GetJsonData(false))
|
||||
|
||||
case sg.OutputType.IsGraph():
|
||||
if table == nil {
|
||||
break
|
||||
}
|
||||
sg.Error = table.SetGraphFromJson(output.Json(graphFilter))
|
||||
if sg.Error != nil {
|
||||
break
|
||||
@ -203,6 +214,32 @@ func (sg *SunGrow) GetPsId() (int64, error) {
|
||||
return ret, sg.Error
|
||||
}
|
||||
|
||||
func (sg *SunGrow) GetPsKeys() ([]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.GetPsKeys()
|
||||
}
|
||||
|
||||
return ret, sg.Error
|
||||
}
|
||||
|
||||
func fillArray(count int, args []string) []string {
|
||||
var ret []string
|
||||
for range Only.Once {
|
||||
|
@ -3,16 +3,20 @@ package iSolarCloud
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/iSolarCloud/AppService/getPowerDevicePointNames"
|
||||
"GoSungrow/iSolarCloud/AppService/getPsDetailWithPsType"
|
||||
"GoSungrow/iSolarCloud/AppService/getPsList"
|
||||
"GoSungrow/iSolarCloud/AppService/getTemplateList"
|
||||
"GoSungrow/iSolarCloud/AppService/queryDeviceList"
|
||||
"GoSungrow/iSolarCloud/AppService/queryDeviceRealTimeDataByPsKeys"
|
||||
"GoSungrow/iSolarCloud/AppService/queryMutiPointDataList"
|
||||
"GoSungrow/iSolarCloud/WebAppService/getMqttConfigInfoByAppkey"
|
||||
"GoSungrow/iSolarCloud/WebAppService/queryUserCurveTemplateData"
|
||||
"GoSungrow/iSolarCloud/api"
|
||||
"GoSungrow/iSolarCloud/api/output"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -103,7 +107,7 @@ func (sg *SunGrow) GetTemplateData(template string, date string, filter string)
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep, table, filter)
|
||||
sg.Error = sg.Output(ep, &table, filter)
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
@ -251,13 +255,11 @@ func (sg *SunGrow) PrintCurrentStats() error {
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(_getPsList, table, "")
|
||||
sg.Error = sg.Output(_getPsList, &table, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// ep = sg.GetByJson("AppService.queryDeviceList", fmt.Sprintf(`{"ps_id":"%d"}`, psId))
|
||||
ep = sg.GetByStruct(
|
||||
"AppService.queryDeviceList",
|
||||
queryDeviceList.RequestData{PsId: strconv.FormatInt(psId, 10)},
|
||||
@ -274,7 +276,7 @@ func (sg *SunGrow) PrintCurrentStats() error {
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep2, table, "")
|
||||
sg.Error = sg.Output(ep2, &table, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
@ -328,7 +330,7 @@ func (sg *SunGrow) GetPointNames() error {
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep2, table, "")
|
||||
sg.Error = sg.Output(ep2, &table, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
@ -356,7 +358,113 @@ func (sg *SunGrow) GetTemplates() error {
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep2, table, "")
|
||||
sg.Error = sg.Output(ep2, &table, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return sg.Error
|
||||
}
|
||||
|
||||
func (sg *SunGrow) GetIsolarcloudMqtt(appKey string) error {
|
||||
for range Only.Once {
|
||||
if appKey == "" {
|
||||
appKey = sg.GetAppKey()
|
||||
}
|
||||
|
||||
ep := sg.GetByStruct(
|
||||
"WebAppService.getMqttConfigInfoByAppkey",
|
||||
getMqttConfigInfoByAppkey.RequestData{AppKey: appKey},
|
||||
DefaultCacheTimeout,
|
||||
)
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
ep2 := getMqttConfigInfoByAppkey.Assert(ep)
|
||||
table := ep2.GetDataTable()
|
||||
if table.Error != nil {
|
||||
sg.Error = table.Error
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep2, &table, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return sg.Error
|
||||
}
|
||||
|
||||
func (sg *SunGrow) GetRealTimeData(psKey string) error {
|
||||
for range Only.Once {
|
||||
if psKey == "" {
|
||||
var psKeys []string
|
||||
psKeys, sg.Error = sg.GetPsKeys()
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
fmt.Printf("%v\n", psKeys)
|
||||
psKey = strings.Join(psKeys, ",")
|
||||
}
|
||||
|
||||
ep := sg.GetByStruct(
|
||||
"AppService.queryDeviceRealTimeDataByPsKeys",
|
||||
queryDeviceRealTimeDataByPsKeys.RequestData{PsKeyList: psKey},
|
||||
DefaultCacheTimeout,
|
||||
)
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
|
||||
ep2 := queryDeviceRealTimeDataByPsKeys.Assert(ep)
|
||||
table := ep2.GetDataTable()
|
||||
if table.Error != nil {
|
||||
sg.Error = table.Error
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep2, nil, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return sg.Error
|
||||
}
|
||||
|
||||
func (sg *SunGrow) GetPsDetails(psid string) error {
|
||||
|
||||
for range Only.Once {
|
||||
var psId int64
|
||||
if psid == "" {
|
||||
psId, sg.Error = sg.GetPsId()
|
||||
} else {
|
||||
psId, sg.Error = strconv.ParseInt(psid, 10, 64)
|
||||
}
|
||||
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)
|
||||
table := ep2.GetDataTable()
|
||||
if table.Error != nil {
|
||||
sg.Error = table.Error
|
||||
break
|
||||
}
|
||||
|
||||
sg.Error = sg.Output(ep2, &table, "")
|
||||
if sg.Error != nil {
|
||||
break
|
||||
}
|
||||
|
1
iSolarCloud/points.go
Normal file
@ -0,0 +1 @@
|
||||
package iSolarCloud
|
@ -20,6 +20,7 @@ type SunGrow struct {
|
||||
Auth login.EndPoint
|
||||
Areas api.Areas
|
||||
Error error
|
||||
NeedLogin bool
|
||||
|
||||
OutputType output.OutputType
|
||||
// EndPoint api.EndPoint
|
||||
|
1
mmMqtt/cron.go
Normal file
@ -0,0 +1 @@
|
||||
package mmMqtt
|
@ -96,6 +96,7 @@ type Sensor struct {
|
||||
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:"-"`
|
||||
//
|
||||
|
246
mmMqtt/struct.go
@ -2,6 +2,8 @@ package mmMqtt
|
||||
|
||||
import (
|
||||
"GoSungrow/Only"
|
||||
"GoSungrow/iSolarCloud/api"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
@ -13,17 +15,21 @@ import (
|
||||
|
||||
|
||||
type Mqtt struct {
|
||||
ClientId string `json:"client_id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
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
|
||||
url *url.URL
|
||||
client mqtt.Client
|
||||
pubClient mqtt.Client
|
||||
clientOptions *mqtt.ClientOptions
|
||||
err error
|
||||
LastRefresh time.Time `json:"-"`
|
||||
PsId int64 `json:"-"`
|
||||
|
||||
firstRun bool
|
||||
err error
|
||||
}
|
||||
|
||||
func New(req Mqtt) *Mqtt {
|
||||
@ -34,11 +40,24 @@ func New(req Mqtt) *Mqtt {
|
||||
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
|
||||
}
|
||||
@ -50,6 +69,20 @@ func (m *Mqtt) IsError() bool {
|
||||
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 {
|
||||
@ -66,7 +99,7 @@ func (m *Mqtt) setUrl(req Mqtt) error {
|
||||
m.Password = req.Password
|
||||
|
||||
if req.Host == "" {
|
||||
m.err = errors.New("host empty")
|
||||
m.err = errors.New("HASSIO mqtt host not defined")
|
||||
break
|
||||
}
|
||||
m.Host = req.Host
|
||||
@ -197,13 +230,14 @@ func (m *Mqtt) SensorPublish(subtopic string, payload interface{}) error {
|
||||
return m.err
|
||||
}
|
||||
|
||||
func (m *Mqtt) SensorPublishConfig(id string, name string, units string, address int) error {
|
||||
// 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(address)
|
||||
id = strings.ReplaceAll("sungrow_" + id, ".", "-")
|
||||
a := strconv.Itoa(point.Index)
|
||||
id := strings.ReplaceAll("sungrow_" + point.PointId, ".", "-")
|
||||
|
||||
class := ""
|
||||
switch units {
|
||||
switch point.Unit {
|
||||
case "MW":
|
||||
fallthrough
|
||||
case "kW":
|
||||
@ -237,35 +271,74 @@ func (m *Mqtt) SensorPublishConfig(id string, name string, units string, address
|
||||
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: name,
|
||||
Name: point.PointName,
|
||||
SwVersion: "GoSunGrow https://github.com/MickMake/GoSungrow",
|
||||
ViaDevice: "gosungrow",
|
||||
},
|
||||
Name: "SunGrow " + name,
|
||||
StateClass: "measurement",
|
||||
StateTopic: SensorBaseTopic + "/" + id + "/state",
|
||||
UniqueId: id,
|
||||
UnitOfMeasurement: units,
|
||||
DeviceClass: class,
|
||||
Qos: 0,
|
||||
ForceUpdate: true,
|
||||
ExpireAfter: 0,
|
||||
Encoding: "utf-8",
|
||||
EnabledByDefault: true,
|
||||
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() }}",
|
||||
}
|
||||
|
||||
topic := SensorBaseTopic + "/" + id + "/config"
|
||||
m.client.Publish(topic, 0, true, payload.Json())
|
||||
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, ".", "-")
|
||||
@ -274,105 +347,20 @@ func (m *Mqtt) SensorPublishState(id string, payload interface{}) error {
|
||||
return m.err
|
||||
}
|
||||
|
||||
type MqttState struct {
|
||||
LastReset string `json:"last_reset,omitempty"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// func (m *Mqtt) SetKeyFile(path string) error {
|
||||
//
|
||||
// for range Only.Once {
|
||||
// if path == "" {
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// m.err = checkKeyFile(path)
|
||||
// if m.err != nil {
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// m.KeyFile = path
|
||||
// }
|
||||
//
|
||||
// return m.err
|
||||
// }
|
||||
//
|
||||
// func (m *Mqtt) SetToken(t string) error {
|
||||
//
|
||||
// for range Only.Once {
|
||||
// if t == "" {
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// m.Token = t
|
||||
// }
|
||||
//
|
||||
// return m.err
|
||||
// }
|
||||
//
|
||||
// func (m *Mqtt) SetRepo(repo string) error {
|
||||
//
|
||||
// for range Only.Once {
|
||||
// if repo == "" {
|
||||
// m.err = errors.New("repo empty")
|
||||
// break
|
||||
// }
|
||||
// m.RepoUrl = repo
|
||||
// }
|
||||
//
|
||||
// return m.err
|
||||
// }
|
||||
//
|
||||
// func (m *Mqtt) SetDir(dir string) error {
|
||||
//
|
||||
// for range Only.Once {
|
||||
// if dir == "" {
|
||||
// m.err = errors.New("dir empty")
|
||||
// break
|
||||
// }
|
||||
// m.RepoDir = dir
|
||||
// }
|
||||
//
|
||||
// return m.err
|
||||
// }
|
||||
//
|
||||
// func (m *Mqtt) SetDiffCmd(cmd string) error {
|
||||
//
|
||||
// for range Only.Once {
|
||||
// if cmd == "" {
|
||||
// cmd = "tkdiff"
|
||||
// }
|
||||
// m.DiffCmd = cmd
|
||||
// }
|
||||
//
|
||||
// return m.err
|
||||
// }
|
||||
//
|
||||
// func (m *Mqtt) IsOk() bool {
|
||||
// var ok bool
|
||||
//
|
||||
// for range Only.Once {
|
||||
// //if m.ApiUsername == "" {
|
||||
// // m.Error = errors.New("username empty")
|
||||
// // break
|
||||
// //}
|
||||
// //
|
||||
// //if m.ApiPassword == "" {
|
||||
// // m.Error = errors.New("password empty")
|
||||
// // break
|
||||
// //}
|
||||
//
|
||||
// if m.RepoUrl == "" {
|
||||
// m.err = errors.New("repo empty")
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// if m.RepoDir == "" {
|
||||
// m.err = errors.New("repo dir empty")
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// ok = true
|
||||
// }
|
||||
//
|
||||
// return ok
|
||||
// }
|
||||
// func (m *Mqtt) IsNotOk() bool {
|
||||
// return !m.IsOk()
|
||||
// }
|
||||
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
|
||||
}
|