-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a545b42
commit 6b466cd
Showing
13 changed files
with
374 additions
and
290 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package homeassistant | ||
|
||
type DeviceClass string | ||
|
||
const ( | ||
DeviceClassEnergy DeviceClass = "energy" | ||
DeviceClassBattery DeviceClass = "battery" | ||
DeviceClassPower DeviceClass = "power" | ||
) | ||
|
||
type StateClass string | ||
|
||
const ( | ||
StateClassMeasurement StateClass = "measurement" | ||
StateClassTotalIncreasing StateClass = "total_increasing" | ||
) | ||
|
||
type Unit string | ||
|
||
const ( | ||
UnitKilowattHours Unit = "kWh" | ||
UnitWatt Unit = "W" | ||
UnitPercent Unit = "%" | ||
) | ||
|
||
type Icon string | ||
|
||
const ( | ||
IconSolarPower Icon = "mdi:solar-power" | ||
IconBatteryPlus Icon = "mdi:battery-plus" | ||
IconBatteryMinus Icon = "mdi:battery-minus" | ||
) | ||
|
||
type Sensor struct { | ||
Name string `json:"name"` | ||
Icon Icon `json:"icon,omitempty"` | ||
DeviceClass DeviceClass `json:"device_class,omitempty"` | ||
StateTopic string `json:"state_topic"` | ||
StateClass StateClass `json:"state_class,omitempty"` | ||
UnitOfMeasurement Unit `json:"unit_of_measurement,omitempty"` | ||
ValueTemplate string `json:"value_template,omitempty"` | ||
UniqueId string `json:"unique_id,omitempty"` | ||
Device Device `json:"device,omitempty"` | ||
} | ||
|
||
type Device struct { | ||
Identifiers []string `json:"identifiers,omitempty"` | ||
Name string `json:"name,omitempty"` | ||
Manufacturer string `json:"manufacturer,omitempty"` | ||
Model string `json:"model,omitempty"` | ||
SerialNumber string `json:"serial_number,omitempty"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package homeassistant | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
mqtt "github.com/eclipse/paho.mqtt.golang" | ||
"log/slog" | ||
"strings" | ||
) | ||
|
||
type Options struct { | ||
MqttClient mqtt.Client | ||
TopicPrefix string | ||
} | ||
|
||
type Service struct { | ||
options Options | ||
} | ||
|
||
func NewService(opts Options) *Service { | ||
return &Service{ | ||
options: opts, | ||
} | ||
} | ||
|
||
func (s *Service) SendSensorDiscoveryPayload(sensors []Sensor) { | ||
for _, sensor := range sensors { | ||
if b, err := json.Marshal(sensor); err != nil { | ||
slog.Error("could not marshal sensor discovery payload", slog.Any("sensor", sensor)) | ||
} else { | ||
topic := s.sensorTopic(sensor) | ||
s.options.MqttClient.Publish(topic, 1, false, string(b)) | ||
} | ||
} | ||
} | ||
|
||
func (s *Service) sensorTopic(sensor Sensor) string { | ||
return fmt.Sprintf("%s/sensor/%s/%s/config", s.options.TopicPrefix, fmt.Sprintf("noah_%s", sensor.Device.SerialNumber), strings.ReplaceAll(sensor.Name, " ", "")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package homeassistant | ||
|
||
import "fmt" | ||
|
||
func (s *Service) GenerateSensorDiscoveryPayload(deviceName string, serialNumber string, stateTopic string) []Sensor { | ||
device := Device{ | ||
Identifiers: []string{fmt.Sprintf("noah_%s", serialNumber)}, | ||
Name: deviceName, | ||
Manufacturer: "Growatt", | ||
Model: "Noah", | ||
SerialNumber: serialNumber, | ||
} | ||
|
||
return []Sensor{ | ||
{ | ||
Name: "Output Power", | ||
DeviceClass: DeviceClassPower, | ||
StateClass: StateClassMeasurement, | ||
StateTopic: stateTopic, | ||
UnitOfMeasurement: UnitWatt, | ||
ValueTemplate: "{{ value_json.output_w }}", | ||
UniqueId: fmt.Sprintf("%s_%s", serialNumber, "output_power"), | ||
Device: device, | ||
}, | ||
{ | ||
Name: "Solar Power", | ||
Icon: IconSolarPower, | ||
DeviceClass: DeviceClassPower, | ||
StateClass: StateClassMeasurement, | ||
StateTopic: stateTopic, | ||
UnitOfMeasurement: UnitWatt, | ||
ValueTemplate: "{{ value_json.solar_w }}", | ||
UniqueId: fmt.Sprintf("%s_%s", serialNumber, "solar_power"), | ||
Device: device, | ||
}, | ||
{ | ||
Name: "Charging Power", | ||
Icon: IconBatteryPlus, | ||
DeviceClass: DeviceClassPower, | ||
StateClass: StateClassMeasurement, | ||
StateTopic: stateTopic, | ||
UnitOfMeasurement: UnitWatt, | ||
ValueTemplate: "{{ value_json.charge_w }}", | ||
UniqueId: fmt.Sprintf("%s_%s", serialNumber, "charging_power"), | ||
Device: device, | ||
}, | ||
{ | ||
Name: "Discharge Power", | ||
Icon: IconBatteryMinus, | ||
DeviceClass: DeviceClassPower, | ||
StateClass: StateClassMeasurement, | ||
StateTopic: stateTopic, | ||
UnitOfMeasurement: UnitWatt, | ||
ValueTemplate: "{{ value_json.discharge_w }}", | ||
UniqueId: fmt.Sprintf("%s_%s", serialNumber, "discharge_power"), | ||
Device: device, | ||
}, | ||
{ | ||
Name: "Generation Total", | ||
DeviceClass: DeviceClassEnergy, | ||
StateClass: StateClassTotalIncreasing, | ||
StateTopic: stateTopic, | ||
UnitOfMeasurement: UnitKilowattHours, | ||
ValueTemplate: "{{ value_json.generation_total_kwh }}", | ||
UniqueId: fmt.Sprintf("%s_%s", serialNumber, "generation_total"), | ||
Device: device, | ||
}, | ||
{ | ||
Name: "Generation Today", | ||
DeviceClass: DeviceClassEnergy, | ||
StateClass: StateClassTotalIncreasing, | ||
StateTopic: stateTopic, | ||
UnitOfMeasurement: UnitKilowattHours, | ||
ValueTemplate: "{{ value_json.generation_today_kwh }}", | ||
UniqueId: fmt.Sprintf("%s_%s", serialNumber, "generation_today"), | ||
Device: device, | ||
}, | ||
{ | ||
Name: "SoC", | ||
DeviceClass: DeviceClassBattery, | ||
StateClass: StateClassMeasurement, | ||
StateTopic: stateTopic, | ||
UnitOfMeasurement: UnitPercent, | ||
ValueTemplate: "{{ value_json.soc }}", | ||
UniqueId: fmt.Sprintf("%s_%s", serialNumber, "soc"), | ||
Device: device, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package polling | ||
|
||
import ( | ||
"noah-mqtt/internal/growatt" | ||
"noah-mqtt/pkg/models" | ||
"strconv" | ||
) | ||
|
||
func noahStatusToPayload(n *growatt.NoahStatus) models.Payload { | ||
return models.Payload{ | ||
OutputPower: parseFloat(n.Obj.Pac), | ||
SolarPower: parseFloat(n.Obj.Ppv), | ||
Soc: parseFloat(n.Obj.Soc), | ||
ChargePower: parseFloat(n.Obj.ChargePower), | ||
DischargePower: parseFloat(n.Obj.DisChargePower), | ||
BatteryNum: int(parseFloat(n.Obj.BatteryNum)), | ||
GenerationTotalEnergy: parseFloat(n.Obj.EacTotal), | ||
GenerationTodayEnergy: parseFloat(n.Obj.EacToday), | ||
WorkMode: workModeFromString(n.Obj.WorkMode), | ||
} | ||
} | ||
|
||
func workModeFromString(s string) models.WorkMode { | ||
if s == "0" { | ||
return models.WorkModeLoadFirst | ||
} | ||
return models.WorkModeBatteryFirst | ||
} | ||
|
||
func parseFloat(s string) float64 { | ||
if s, err := strconv.ParseFloat(s, 64); err == nil { | ||
return s | ||
} else { | ||
return 0 | ||
} | ||
} |
Oops, something went wrong.