chore: fix linter (#11028)
This commit is contained in:
parent
098a0fc2b5
commit
58e2421a5b
91 changed files with 374 additions and 280 deletions
|
|
@ -1,10 +1,55 @@
|
|||
run:
|
||||
go: "1.21"
|
||||
|
||||
issues:
|
||||
exclude:
|
||||
- .regActualCurrent. is unused
|
||||
- "`routeLogger` is unused"
|
||||
|
||||
linters-settings:
|
||||
staticcheck:
|
||||
checks:
|
||||
- "-SA1019"
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- dogsled
|
||||
- durationcheck
|
||||
- exportloopref
|
||||
- gci
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- goprintffuncname
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- makezero
|
||||
- misspell
|
||||
- nolintlint
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- tparallel
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unused
|
||||
- wastedassign
|
||||
- whitespace
|
||||
|
||||
# fixme
|
||||
# - bodyclose
|
||||
# - exhaustive
|
||||
# - gocritic
|
||||
# - godot
|
||||
# - gomoddirectives
|
||||
# - nakedret
|
||||
# - nilerr
|
||||
# - noctx
|
||||
# - prealloc
|
||||
# - predeclared
|
||||
# - revive
|
||||
# - stylecheck
|
||||
# - unparam
|
||||
# - dupl
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ func NewAlphatec(uri, device, comset string, baudrate int, proto modbus.Protocol
|
|||
|
||||
func (wb *Alphatec) setCurrent(current uint16) error {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, uint16(current))
|
||||
binary.BigEndian.PutUint16(b, current)
|
||||
|
||||
_, err := wb.conn.WriteMultipleRegisters(alphatecRegAmpsConfig, 1, b)
|
||||
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ func (c *Easee) ProductUpdate(i json.RawMessage) {
|
|||
}
|
||||
|
||||
// OpMode changed FROM >1 ("car connected") TO 1/disconnected - stop ticker if channel exists
|
||||
// channel may not exist regulary if the car was connected but charging never started
|
||||
// channel may not exist regularly if the car was connected but charging never started
|
||||
if c.opMode != easee.ModeDisconnected && opMode == easee.ModeDisconnected && c.stopTicker != nil {
|
||||
close(c.stopTicker)
|
||||
c.stopTicker = nil
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ const (
|
|||
LOCAL_PRE_AUTHORIZE_ENABLED ObservationID = 15 // Preauthorize with whitelist enabled. Readback on setting [event] [Boolean]
|
||||
LOCAL_AUTHORIZE_OFFLINE_ENABLED ObservationID = 16 // Allow offline charging for whitelisted RFID token. Readback on setting [event] [Boolean]
|
||||
ALLOW_OFFLINE_TX_FOR_UNKNOWN_ID ObservationID = 17 // Allow offline charging for all RFID tokens. Readback on setting [event] [Boolean]
|
||||
ERRATIC_EVMAX_TOGGLES ObservationID = 18 // 0 == erratic checking disabled, otherwise the number of toggles between states Charging and Charging Complate that will trigger an error [Integer]
|
||||
ERRATIC_EVMAX_TOGGLES ObservationID = 18 // 0 == erratic checking disabled, otherwise the number of toggles between states Charging and Charging Complete that will trigger an error [Integer]
|
||||
BACKPLATE_TYPE ObservationID = 19 // Readback on backplate type [Integer]
|
||||
SITE_STRUCTURE ObservationID = 20 // Site Structure [boot] [String]
|
||||
DETECTED_POWER_GRID_TYPE ObservationID = 21 // Detected power grid type according to PowerGridType table [boot] [Integer]
|
||||
|
|
@ -94,7 +94,7 @@ const (
|
|||
FORCED_THREE_PHASE_ON_ITWITH_GND_FAULT ObservationID = 39 // Default disabled. Must be set manually if grid type is indeed three phase IT [Boolean]
|
||||
LED_STRIP_BRIGHTNESS ObservationID = 40 // LED strip brightness, 0-100% [Integer]
|
||||
LOCAL_AUTHORIZATION_REQUIRED ObservationID = 41 // Local RFID authorization is required for charging [user options] [event] [Boolean]
|
||||
AUTHORIZATION_REQUIRED ObservationID = 42 // Authorization is requried for charging [Boolean]
|
||||
AUTHORIZATION_REQUIRED ObservationID = 42 // Authorization is required for charging [Boolean]
|
||||
REMOTE_START_REQUIRED ObservationID = 43 // Remote start required flag [event] [Boolean]
|
||||
SMART_BUTTON_ENABLED ObservationID = 44 // Smart button is enabled [Boolean]
|
||||
OFFLINE_CHARGING_MODE ObservationID = 45 // Charger behavior when offline [Integer]
|
||||
|
|
|
|||
|
|
@ -36,12 +36,10 @@ func NewWattpilotFromConfig(other map[string]interface{}) (api.Charger, error) {
|
|||
}
|
||||
|
||||
return NewWattpilot(cc.URI, cc.Password, cc.Cache)
|
||||
|
||||
}
|
||||
|
||||
// NewWattpilot creates Wattpilot charger
|
||||
func NewWattpilot(uri, password string, cache time.Duration) (api.Charger, error) {
|
||||
|
||||
c := &Wattpilot{
|
||||
api: wattpilot.New(uri, password),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func (c *LocalAPI) upgradeV2() {
|
|||
err := c.response("api/status?filter=alw", &res)
|
||||
|
||||
if err == nil {
|
||||
c.uri = c.uri + "/api"
|
||||
c.uri += "/api"
|
||||
} else {
|
||||
c.v2 = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ func (wb *HuaweiACCharger) Status() (api.ChargeStatus, error) {
|
|||
return api.StatusNone, err
|
||||
}
|
||||
|
||||
//ToDo: Real status
|
||||
// ToDo: Real status
|
||||
switch u := binary.BigEndian.Uint16(b); u {
|
||||
case 0:
|
||||
return api.StatusA, nil
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ func (mcc *MobileConnect) fetchToken(request *http.Request) error {
|
|||
}
|
||||
|
||||
// login as the home user with the given password
|
||||
func (mcc *MobileConnect) login(password string) error {
|
||||
func (mcc *MobileConnect) login() error {
|
||||
uri := fmt.Sprintf("%s/%s", mcc.uri, mccAPILogin)
|
||||
|
||||
data := url.Values{
|
||||
|
|
@ -170,7 +170,7 @@ func (mcc *MobileConnect) request(method, uri string) (*http.Request, error) {
|
|||
|
||||
// do we need to login?
|
||||
if mcc.token == "" {
|
||||
if err := mcc.login(mcc.password); err != nil {
|
||||
if err := mcc.login(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ type apiResponse struct {
|
|||
// NewTestClient returns *http.Client with Transport replaced to avoid making real calls
|
||||
func NewTestClient(fn roundTripFunc) *http.Client {
|
||||
return &http.Client{
|
||||
Transport: roundTripFunc(fn),
|
||||
Transport: fn,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,13 +50,13 @@ func NewTestMobileConnect(t *testing.T, responses []apiResponse) *MobileConnect
|
|||
// response string for the currently invoked call
|
||||
var responseString string
|
||||
for _, s := range responses {
|
||||
if strings.Contains("/"+string(s.apiCall), req.URL.Path) {
|
||||
if strings.Contains("/"+s.apiCall, req.URL.Path) {
|
||||
responseString = s.apiResponse
|
||||
}
|
||||
}
|
||||
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
StatusCode: http.StatusOK,
|
||||
// Send response to be tested
|
||||
Body: io.NopCloser(bytes.NewBufferString(responseString)),
|
||||
// Must be set to non-nil value or it panics
|
||||
|
|
@ -83,7 +83,7 @@ func TestMobileConnectLogin(t *testing.T) {
|
|||
t.Run(tc.name, func(t *testing.T) {
|
||||
mcc := NewTestMobileConnect(t, tc.responses)
|
||||
|
||||
if err := mcc.login(tc.password); (err != nil) != tc.wantErr {
|
||||
if err := mcc.login(); (err != nil) != tc.wantErr {
|
||||
t.Errorf("MobileConnect.login() error = %v, wantErr %v", err, tc.wantErr)
|
||||
}
|
||||
})
|
||||
|
|
@ -263,13 +263,15 @@ func TestMobileConnectCurrentPower(t *testing.T) {
|
|||
"no data response",
|
||||
[]apiResponse{
|
||||
{mccAPIEnergy, "\"\"\n"},
|
||||
}, 0, false,
|
||||
},
|
||||
0, false,
|
||||
},
|
||||
{
|
||||
"home plug - error response",
|
||||
[]apiResponse{
|
||||
{mccAPIEnergy, "\"{\\n \\\"L1\\\": {\\n \\\"Ampere\\\": 0,\\n \\\"Power\\\": 0,\\n \\\"Volts\\\": 246.60000000000002\\n },\\n \\\"L2\\\": {\\n \\\"Ampere\\\": 0,\\n \\\"Power\\\": 0,\\n \\\"Volts\\\": 16.800000000000001\\n },\\n \\\"L3\\\": {\\n \\\"Ampere\\\": 0,\\n \\\"Power\\\": 0,\\n \\\"Volts\\\": 16.300000000000001\\n }\\n}\\n\""},
|
||||
}, 0, false,
|
||||
},
|
||||
0, false,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
|
|
@ -300,19 +302,22 @@ func TestMobileConnectChargedEnergy(t *testing.T) {
|
|||
"valid response",
|
||||
[]apiResponse{
|
||||
{mccAPICurrentSession, "\"{\\n \\\"account\\\": \\\"PRIVATE\\\",\\n \\\"chargingRate\\\": 0,\\n \\\"chargingType\\\": \\\"AC\\\",\\n \\\"clockSrc\\\": \\\"NTP\\\",\\n \\\"costs\\\": 0,\\n \\\"currency\\\": \\\"\\\",\\n \\\"departTime\\\": \\\"\\\",\\n \\\"duration\\\": 30789,\\n \\\"endOfChargeTime\\\": \\\"\\\",\\n \\\"endSoc\\\": 0,\\n \\\"endTime\\\": \\\"\\\",\\n \\\"energySumKwh\\\": 18.832000000000001,\\n \\\"evChargingRatekW\\\": 0,\\n \\\"evTargetSoc\\\": -1,\\n \\\"evVasAvailability\\\": false,\\n \\\"pcid\\\": \\\"\\\",\\n \\\"powerRange\\\": 0,\\n \\\"selfEnergy\\\": 0,\\n \\\"sessionId\\\": 13,\\n \\\"soc\\\": -1,\\n \\\"solarEnergyShare\\\": 0,\\n \\\"startSoc\\\": 0,\\n \\\"startTime\\\": \\\"2020-04-15T10:07:22+02:00\\\",\\n \\\"totalRange\\\": 0,\\n \\\"vehicleBrand\\\": \\\"\\\",\\n \\\"vehicleModel\\\": \\\"\\\",\\n \\\"whitelist\\\": false\\n}\\n\""},
|
||||
}, 18.832000000000001, false,
|
||||
},
|
||||
18.832000000000001, false,
|
||||
},
|
||||
{
|
||||
"no data response",
|
||||
[]apiResponse{
|
||||
{mccAPICurrentSession, "\"\"\n"},
|
||||
}, 0, false,
|
||||
},
|
||||
0, false,
|
||||
},
|
||||
{
|
||||
"error response",
|
||||
[]apiResponse{
|
||||
{mccAPICurrentSession, "invalidjson"},
|
||||
}, 0, true,
|
||||
},
|
||||
0, true,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
|
|
@ -342,19 +347,22 @@ func TestMobileConnectChargingTime(t *testing.T) {
|
|||
"valid response",
|
||||
[]apiResponse{
|
||||
{mccAPICurrentSession, "\"{\\n \\\"account\\\": \\\"PRIVATE\\\",\\n \\\"chargingRate\\\": 0,\\n \\\"chargingType\\\": \\\"AC\\\",\\n \\\"clockSrc\\\": \\\"NTP\\\",\\n \\\"costs\\\": 0,\\n \\\"currency\\\": \\\"\\\",\\n \\\"departTime\\\": \\\"\\\",\\n \\\"duration\\\": 30789,\\n \\\"endOfChargeTime\\\": \\\"\\\",\\n \\\"endSoc\\\": 0,\\n \\\"endTime\\\": \\\"\\\",\\n \\\"energySumKwh\\\": 18.832000000000001,\\n \\\"evChargingRatekW\\\": 0,\\n \\\"evTargetSoc\\\": -1,\\n \\\"evVasAvailability\\\": false,\\n \\\"pcid\\\": \\\"\\\",\\n \\\"powerRange\\\": 0,\\n \\\"selfEnergy\\\": 0,\\n \\\"sessionId\\\": 13,\\n \\\"soc\\\": -1,\\n \\\"solarEnergyShare\\\": 0,\\n \\\"startSoc\\\": 0,\\n \\\"startTime\\\": \\\"2020-04-15T10:07:22+02:00\\\",\\n \\\"totalRange\\\": 0,\\n \\\"vehicleBrand\\\": \\\"\\\",\\n \\\"vehicleModel\\\": \\\"\\\",\\n \\\"whitelist\\\": false\\n}\\n\""},
|
||||
}, 30789 * time.Second, false,
|
||||
},
|
||||
30789 * time.Second, false,
|
||||
},
|
||||
{
|
||||
"no data response",
|
||||
[]apiResponse{
|
||||
{mccAPICurrentSession, "\"\"\n"},
|
||||
}, 0, false,
|
||||
},
|
||||
0, false,
|
||||
},
|
||||
{
|
||||
"error response",
|
||||
[]apiResponse{
|
||||
{mccAPICurrentSession, "invalidjson"},
|
||||
}, 0, true,
|
||||
},
|
||||
0, true,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
|
|
@ -399,13 +407,15 @@ func TestMobileConnectCurrents(t *testing.T) {
|
|||
"no data response",
|
||||
[]apiResponse{
|
||||
{mccAPIEnergy, "\"\"\n"},
|
||||
}, 0, 0, 0, false,
|
||||
},
|
||||
0, 0, 0, false,
|
||||
},
|
||||
{
|
||||
"home plug - error response",
|
||||
[]apiResponse{
|
||||
{mccAPIEnergy, "\"{\\n \\\"L1\\\": {\\n \\\"Ampere\\\": 0,\\n \\\"Power\\\": 0,\\n \\\"Volts\\\": 246.60000000000002\\n },\\n \\\"L2\\\": {\\n \\\"Ampere\\\": 0,\\n \\\"Power\\\": 0,\\n \\\"Volts\\\": 16.800000000000001\\n },\\n \\\"L3\\\": {\\n \\\"Ampere\\\": 0,\\n \\\"Power\\\": 0,\\n \\\"Volts\\\": 16.300000000000001\\n }\\n}\\n\""},
|
||||
}, 0, 0, 0, false,
|
||||
},
|
||||
0, 0, 0, false,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
|
|
|
|||
|
|
@ -109,16 +109,16 @@ func (suite *ocppTestSuite) TestConnect() {
|
|||
|
||||
// status
|
||||
_, err = c1.Status()
|
||||
suite.NoError(err)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// power
|
||||
f, err := c1.currentPower()
|
||||
suite.NoError(err)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(1e3, f)
|
||||
|
||||
// energy
|
||||
f, err = c1.totalEnergy()
|
||||
suite.NoError(err)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(1.2, f)
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ func (suite *ocppTestSuite) TestConnect() {
|
|||
|
||||
res, err := cp1.StopTransaction(0, types.NewDateTime(suite.clock.Now()), expectedTxn)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(res.IdTagInfo.Status, types.AuthorizationStatusAccepted)
|
||||
suite.Equal(types.AuthorizationStatusAccepted, res.IdTagInfo.Status)
|
||||
}
|
||||
|
||||
// 2nd charge point - remote
|
||||
|
|
@ -166,7 +166,7 @@ func (suite *ocppTestSuite) TestConnect() {
|
|||
|
||||
// status
|
||||
_, err = c2.Status()
|
||||
suite.NoError(err)
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
// error on unconfigured 2nd charge point
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package charger
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
|
|
@ -69,7 +70,7 @@ func (wb *Pantabox) Enabled() (bool, error) {
|
|||
|
||||
// Enable implements the api.Charger interface
|
||||
func (wb *Pantabox) Enable(enable bool) error {
|
||||
resp, err := wb.Post(wb.uri+"/charger/enable", request.PlainContent, strings.NewReader(fmt.Sprintf("%t", enable)))
|
||||
resp, err := wb.Post(wb.uri+"/charger/enable", request.PlainContent, strings.NewReader(strconv.FormatBool(enable)))
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
|
||||
|
|
@ -83,7 +84,7 @@ func (wb *Pantabox) Enable(enable bool) error {
|
|||
|
||||
// MaxCurrent implements the api.Charger interface
|
||||
func (wb *Pantabox) MaxCurrent(current int64) error {
|
||||
resp, err := wb.Post(wb.uri+"/charger/current", request.PlainContent, strings.NewReader(fmt.Sprintf("%d", current)))
|
||||
resp, err := wb.Post(wb.uri+"/charger/current", request.PlainContent, strings.NewReader(strconv.FormatInt(current, 10)))
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ type SendParameter struct {
|
|||
Values []Value `json:"values"`
|
||||
}
|
||||
|
||||
// part of Paramter Send structure
|
||||
// part of Parameter Send structure
|
||||
type Value struct {
|
||||
Timestamp string `json:"timestamp"`
|
||||
ChannelId string `json:"channelId"`
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ var acceptable = []string{
|
|||
|
||||
func TestTemplates(t *testing.T) {
|
||||
templates.TestClass(t, templates.Charger, func(t *testing.T, values map[string]any) {
|
||||
t.Helper()
|
||||
if _, err := NewFromConfig("template", values); err != nil && !test.Acceptable(err, acceptable) {
|
||||
t.Log(values)
|
||||
t.Error(err)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ type Vitals struct {
|
|||
SessionEnergyWh float64 `json:"session_energy_wh"` // 22864.699
|
||||
ConfigStatus int `json:"config_status"` // 5
|
||||
EvseState int `json:"evse_state"` // 1
|
||||
CurrentAlerts []any `json:"current_alerts"` //[]
|
||||
CurrentAlerts []any `json:"current_alerts"` // []
|
||||
}
|
||||
|
||||
// NewTwc3FromConfig creates a new vehicle
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@ func (c *CmdConfigure) configureLinkedTemplate(templateItem templates.Template,
|
|||
if c.askConfigFailureNextStep() {
|
||||
continue
|
||||
}
|
||||
|
||||
} else {
|
||||
c.configuration.AddDevice(deviceItem, category)
|
||||
c.processDeviceCapabilities(templateItem.Capabilities)
|
||||
|
|
|
|||
|
|
@ -76,10 +76,8 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa
|
|||
c.addedDeviceIndex--
|
||||
return device, c.errDeviceNotValid
|
||||
}
|
||||
} else {
|
||||
if deviceCategory == DeviceCategoryCharger && testResult == DeviceTestResultValid {
|
||||
device.ChargerHasMeter = true
|
||||
}
|
||||
} else if deviceCategory == DeviceCategoryCharger && testResult == DeviceTestResultValid {
|
||||
device.ChargerHasMeter = true
|
||||
}
|
||||
|
||||
templateItem.Params = append(templateItem.Params, templates.Param{Name: "name", Value: device.Name})
|
||||
|
|
@ -330,7 +328,7 @@ func (c *CmdConfigure) fetchElements(deviceCategory DeviceCategory) []templates.
|
|||
}
|
||||
}
|
||||
|
||||
sort.Slice(items[:], func(i, j int) bool {
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
// sort generic templates to the bottom
|
||||
if items[i].Group != "" && items[j].Group == "" {
|
||||
return false
|
||||
|
|
@ -376,7 +374,7 @@ func (c *CmdConfigure) processConfig(templateItem *templates.Template, deviceCat
|
|||
fmt.Println(c.localizedString("Config_Title"))
|
||||
fmt.Println()
|
||||
|
||||
c.processModbusConfig(templateItem, deviceCategory)
|
||||
c.processModbusConfig(templateItem)
|
||||
|
||||
return c.processParams(templateItem, deviceCategory)
|
||||
}
|
||||
|
|
@ -485,7 +483,7 @@ func (c *CmdConfigure) processInputConfig(param templates.Param) string {
|
|||
|
||||
// processModbusConfig adds default values from the modbus Param to the template
|
||||
// and handles user input for interface type selection
|
||||
func (c *CmdConfigure) processModbusConfig(templateItem *templates.Template, deviceCategory DeviceCategory) {
|
||||
func (c *CmdConfigure) processModbusConfig(templateItem *templates.Template) {
|
||||
var choices []string
|
||||
var choiceTypes []string
|
||||
|
||||
|
|
|
|||
|
|
@ -209,10 +209,8 @@ func (c *CmdConfigure) flowNewConfigFile() {
|
|||
// in case of permission error, we can't write to the file anyway
|
||||
if os.IsPermission(err) {
|
||||
fmt.Println(c.localizedString("File_Permissions", localizeMap{"FileName": filename}))
|
||||
} else {
|
||||
if c.askYesNo(c.localizedString("File_Exists", localizeMap{"FileName": filename})) {
|
||||
break
|
||||
}
|
||||
} else if c.askYesNo(c.localizedString("File_Exists", localizeMap{"FileName": filename})) {
|
||||
break
|
||||
}
|
||||
|
||||
filename = c.askValue(question{
|
||||
|
|
@ -302,7 +300,6 @@ func (c *CmdConfigure) configureLoadpoints() {
|
|||
fmt.Println(c.localizedString("Loadpoint_Setup"))
|
||||
|
||||
for {
|
||||
|
||||
loadpointTitle := c.askValue(question{
|
||||
label: c.localizedString("Loadpoint_Title"),
|
||||
defaultValue: c.localizedString("Loadpoint_DefaultTitle"),
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ type ModbusHandler struct {
|
|||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func (h *ModbusHandler) testRegister(log *util.Logger, conn gridx.Client) bool {
|
||||
func (h *ModbusHandler) testRegister(_ *util.Logger, conn gridx.Client) bool {
|
||||
var bytes []byte
|
||||
var err error
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ type TcpHandler struct {
|
|||
dialer net.Dialer
|
||||
}
|
||||
|
||||
func (h *TcpHandler) Test(log *util.Logger, in ResultDetails) (res []ResultDetails) {
|
||||
func (h *TcpHandler) Test(_ *util.Logger, in ResultDetails) (res []ResultDetails) {
|
||||
for _, port := range h.Ports {
|
||||
addr := net.JoinHostPort(in.IP, strconv.Itoa(port))
|
||||
conn, err := h.dialer.Dial("tcp", addr)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ func redact(src string) string {
|
|||
"token", "access", "refresh", "accesstoken", "refreshtoken", // tokens, including template variations
|
||||
"ain", "secret", "serial", "deviceid", "machineid", "idtag", // devices
|
||||
"app", "chats", "recipients", // push messaging
|
||||
"vin"} // vehicles
|
||||
"vin", // vehicles
|
||||
}
|
||||
return regexp.
|
||||
MustCompile(fmt.Sprintf(`(?i)\b(%s)\b.*?:.*`, strings.Join(secrets, "|"))).
|
||||
ReplaceAllString(src, "$1: *****")
|
||||
|
|
|
|||
|
|
@ -24,12 +24,11 @@ import (
|
|||
"github.com/evcc-io/evcc/util/telemetry"
|
||||
"github.com/fatih/structs"
|
||||
"github.com/jeremywohl/flatten"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
const rebootDelay = 5 * time.Minute // delayed reboot on error
|
||||
|
|
|
|||
11
cmd/setup.go
11
cmd/setup.go
|
|
@ -645,19 +645,14 @@ func configureSite(conf map[string]interface{}, loadpoints []*core.Loadpoint, ta
|
|||
}
|
||||
|
||||
func configureLoadpoints(conf globalConfig) (loadpoints []*core.Loadpoint, err error) {
|
||||
lpInterfaces, ok := viper.AllSettings()["loadpoints"].([]interface{})
|
||||
if !ok || len(lpInterfaces) == 0 {
|
||||
if len(conf.Loadpoints) == 0 {
|
||||
return nil, errors.New("missing loadpoints")
|
||||
}
|
||||
|
||||
for id, lpcI := range lpInterfaces {
|
||||
var lpc map[string]interface{}
|
||||
if err := util.DecodeOther(lpcI, &lpc); err != nil {
|
||||
return nil, fmt.Errorf("failed decoding loadpoint configuration: %w", err)
|
||||
}
|
||||
|
||||
for id, lpc := range conf.Loadpoints {
|
||||
log := util.NewLoggerWithLoadpoint("lp-"+strconv.Itoa(id+1), id+1)
|
||||
settings := &core.Settings{Key: "lp" + strconv.Itoa(id+1) + "."}
|
||||
|
||||
lp, err := core.NewLoadpointFromConfig(log, settings, lpc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed configuring loadpoint: %w", err)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ func tokenExchangeHandler(oc *oauth2.Config, state string, resC chan *oauth2.Tok
|
|||
token, err := oc.Exchange(ctx, code,
|
||||
oauth2.SetAuthURLParam("grant_type", "code"), // app
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, err)
|
||||
|
|
|
|||
|
|
@ -49,9 +49,7 @@ func generate(out io.Writer, packageName, functionName, baseType string, dynamic
|
|||
return dict, nil
|
||||
},
|
||||
// contains checks if slice contains string
|
||||
"contains": func(combo []string, typ string) bool {
|
||||
return slices.Contains(combo, typ)
|
||||
},
|
||||
"contains": slices.Contains[[]string, string],
|
||||
// ordered returns a slice of typeStructs ordered by dynamicType
|
||||
"ordered": func() []typeStruct {
|
||||
ordered := make([]typeStruct, 0)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ type API interface {
|
|||
// Owner returns the loadpoint that currently owns the vehicle
|
||||
Owner(api.Vehicle) loadpoint.API
|
||||
|
||||
// Aquire acquires the vehicle for the loadpoint and releases it at any other loadpoint
|
||||
// Acquire acquires the vehicle for the loadpoint and releases it at any other loadpoint
|
||||
Acquire(api.Vehicle)
|
||||
|
||||
// Release releases a vehicle from a loadpoint
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package core
|
|||
// EnergyMetrics calculates stats about the charged energy and gives you details about price or co2s
|
||||
type EnergyMetrics struct {
|
||||
totalKWh float64 // Total amount of energy used (kWh)
|
||||
solarKWh float64 // Self-produced energy energy (kWh)
|
||||
solarKWh float64 // Self-produced energy (kWh)
|
||||
price *float64 // Total cost (Currency)
|
||||
co2 *float64 // Amount of emitted CO2 (gCO2eq)
|
||||
currentGreenShare float64 // Current share of solar energy of site (0-1)
|
||||
|
|
|
|||
|
|
@ -28,72 +28,83 @@ func TestEnergyMetrics(t *testing.T) {
|
|||
totalWh, solarPercentage float64
|
||||
price, pricePerKWh, co2PerKWh *float64
|
||||
}{
|
||||
{"initial state",
|
||||
{
|
||||
"initial state",
|
||||
[]tcStep{},
|
||||
0, 0, nil, nil, nil,
|
||||
},
|
||||
{"energy value",
|
||||
{
|
||||
"energy value",
|
||||
[]tcStep{
|
||||
{0.1, 0, nil, nil},
|
||||
{0.2, 0, nil, nil},
|
||||
},
|
||||
200, 0, nil, nil, nil,
|
||||
},
|
||||
{"ignore lower energy value",
|
||||
{
|
||||
"ignore lower energy value",
|
||||
[]tcStep{
|
||||
{0.2, 0, nil, nil},
|
||||
{0.1, 0, nil, nil},
|
||||
},
|
||||
200, 0, nil, nil, nil,
|
||||
},
|
||||
{"half solar",
|
||||
{
|
||||
"half solar",
|
||||
[]tcStep{
|
||||
{0.1, 1, nil, nil},
|
||||
{0.2, 0, nil, nil},
|
||||
},
|
||||
200, 50, nil, nil, nil,
|
||||
},
|
||||
{"only solar",
|
||||
{
|
||||
"only solar",
|
||||
[]tcStep{
|
||||
{0.1, 1, nil, nil},
|
||||
{0.2, 1, nil, nil},
|
||||
},
|
||||
200, 100, nil, nil, nil,
|
||||
},
|
||||
{"static price",
|
||||
{
|
||||
"static price",
|
||||
[]tcStep{
|
||||
{1, 0, f(0.5), nil},
|
||||
},
|
||||
1000, 0, f(0.5), f(0.5), nil,
|
||||
},
|
||||
{"dynamic price",
|
||||
{
|
||||
"dynamic price",
|
||||
[]tcStep{
|
||||
{1, 0, f(1), nil},
|
||||
{2, 0, f(0), nil},
|
||||
},
|
||||
2000, 0, f(1), f(0.5), nil,
|
||||
},
|
||||
{"dynamic price",
|
||||
{
|
||||
"dynamic price",
|
||||
[]tcStep{
|
||||
{2, 0, f(1), nil},
|
||||
{4, 0, f(0), nil},
|
||||
},
|
||||
4000, 0, f(2), f(0.5), nil,
|
||||
},
|
||||
{"static co2",
|
||||
{
|
||||
"static co2",
|
||||
[]tcStep{
|
||||
{1, 0, nil, f(500)},
|
||||
},
|
||||
1000, 0, nil, nil, f(500),
|
||||
},
|
||||
{"dynamic co2",
|
||||
{
|
||||
"dynamic co2",
|
||||
[]tcStep{
|
||||
{1, 0, nil, f(1000)},
|
||||
{2, 0, nil, f(0)},
|
||||
},
|
||||
2000, 0, nil, nil, f(500),
|
||||
},
|
||||
{"grid only, half, full solar, half, grid only",
|
||||
{
|
||||
"grid only, half, full solar, half, grid only",
|
||||
[]tcStep{
|
||||
{1, 0, f(2), f(200)},
|
||||
{2, 0.5, f(1), f(50)},
|
||||
|
|
@ -106,8 +117,6 @@ func TestEnergyMetrics(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
//t.Logf("%+v", tc)
|
||||
|
||||
s := NewEnergyMetrics()
|
||||
|
||||
for _, tc := range tc.steps {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ type Health struct {
|
|||
}
|
||||
|
||||
// NewHealth creates new health checker
|
||||
func NewHealth(timeout time.Duration) (health *Health) {
|
||||
func NewHealth(timeout time.Duration) *Health {
|
||||
return &Health{timeout: timeout}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
evbus "github.com/asaskevich/EventBus"
|
||||
"github.com/avast/retry-go/v4"
|
||||
"github.com/benbjohnson/clock"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core/coordinator"
|
||||
"github.com/evcc-io/evcc/core/keys"
|
||||
|
|
@ -23,10 +26,6 @@ import (
|
|||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/config"
|
||||
"github.com/evcc-io/evcc/util/telemetry"
|
||||
|
||||
evbus "github.com/asaskevich/EventBus"
|
||||
"github.com/avast/retry-go/v4"
|
||||
"github.com/benbjohnson/clock"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -123,6 +123,8 @@ func TestMaxActivePhases(t *testing.T) {
|
|||
}
|
||||
|
||||
func testScale(t *testing.T, lp *Loadpoint, sitePower float64, direction string, tc testCase) {
|
||||
t.Helper()
|
||||
|
||||
act := lp.activePhases()
|
||||
max := lp.maxActivePhases()
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,16 @@ import (
|
|||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSession(t *testing.T) {
|
||||
var err error
|
||||
serverdb.Instance, err = serverdb.New("sqlite", ":memory:")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
db, err := session.NewStore("foo", serverdb.Instance)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
clock := clock.NewMock()
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ func TestSession(t *testing.T) {
|
|||
assert.Equal(t, clock.Now(), lp.session.Finished)
|
||||
|
||||
s, err := db.Sessions()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, s, 1)
|
||||
t.Logf("session: %+v", s)
|
||||
|
||||
|
|
@ -82,7 +83,7 @@ func TestSession(t *testing.T) {
|
|||
assert.Equal(t, clock.Now(), lp.session.Finished)
|
||||
|
||||
s, err = db.Sessions()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, s, 1)
|
||||
t.Logf("session: %+v", s)
|
||||
}
|
||||
|
|
@ -90,32 +91,32 @@ func TestSession(t *testing.T) {
|
|||
func TestCloseSessionsOnStartup_emptyDb(t *testing.T) {
|
||||
var err error
|
||||
serverdb.Instance, err = serverdb.New("sqlite", ":memory:")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
db, err := session.NewStore("foo", serverdb.Instance)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
// assert empty DB is no problem
|
||||
err = db.ClosePendingSessionsInHistory(1000)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCloseSessionsOnStartup(t *testing.T) {
|
||||
var err error
|
||||
serverdb.Instance, err = serverdb.New("sqlite", ":memory:")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
db1, err := session.NewStore("foo", serverdb.Instance)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
db2, err := session.NewStore("bar", serverdb.Instance)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
clock := clock.NewMock()
|
||||
|
||||
// test data, creates 6 sessions for each loadpoint, 3rd and 6th are "unfinished"
|
||||
var sessions1 []*session.Session = createMockSessions(db1, clock)
|
||||
var sessions2 []*session.Session = createMockSessions(db2, clock)
|
||||
sessions1 := createMockSessions(db1, clock)
|
||||
sessions2 := createMockSessions(db2, clock)
|
||||
|
||||
// write interleaved for two loadpoints
|
||||
for index, session := range sessions1 {
|
||||
|
|
@ -124,12 +125,12 @@ func TestCloseSessionsOnStartup(t *testing.T) {
|
|||
}
|
||||
|
||||
err = db1.ClosePendingSessionsInHistory(1000)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
// check fixed sessions for db1
|
||||
var db1Sessions session.Sessions
|
||||
err = serverdb.Instance.Where("Loadpoint = ?", "foo").Order("ID").Find(&db1Sessions).Error
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, db1Sessions, 6)
|
||||
|
||||
// check fixed history
|
||||
|
|
@ -146,7 +147,7 @@ func TestCloseSessionsOnStartup(t *testing.T) {
|
|||
// ensure no side effects on loadpoint 2 data, i.e. data left unfixed
|
||||
var db2Sessions session.Sessions
|
||||
err = serverdb.Instance.Where("Loadpoint = ?", "bar").Order("ID").Find(&db2Sessions).Error
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, db2Sessions, 6)
|
||||
|
||||
for i, s := range db2Sessions {
|
||||
|
|
@ -163,8 +164,7 @@ func TestCloseSessionsOnStartup(t *testing.T) {
|
|||
func createMockSessions(db *session.DB, clock *clock.Mock) []*session.Session {
|
||||
var sessions []*session.Session
|
||||
for i := 1; i <= 6; i++ {
|
||||
|
||||
var meter1Start float64 = float64(i * 10)
|
||||
meter1Start := float64(i * 10)
|
||||
session := db.New(meter1Start)
|
||||
session.Created = clock.Now().Add(1 * time.Minute)
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ func createMockSessions(db *session.DB, clock *clock.Mock) []*session.Session {
|
|||
}
|
||||
|
||||
session.Finished = clock.Now().Add(2 * time.Minute)
|
||||
meterStop := float64(meter1Start + 10)
|
||||
meterStop := meter1Start + 10
|
||||
session.MeterStop = &meterStop
|
||||
session.ChargedEnergy = 10
|
||||
sessions = append(sessions, session)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSyncCharger(t *testing.T) {
|
||||
|
|
@ -42,7 +43,7 @@ func TestSyncCharger(t *testing.T) {
|
|||
enabled: tc.expected,
|
||||
}
|
||||
|
||||
assert.NoError(t, lp.syncCharger())
|
||||
require.NoError(t, lp.syncCharger())
|
||||
assert.Equal(t, tc.corrected, lp.enabled)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ func (n *Null) ChargingTime() (time.Duration, error) {
|
|||
}
|
||||
|
||||
func createChannels(t *testing.T) (chan util.Param, chan push.Event, chan *Loadpoint) {
|
||||
t.Helper()
|
||||
|
||||
uiChan := make(chan util.Param)
|
||||
pushChan := make(chan push.Event)
|
||||
lpChan := make(chan *Loadpoint)
|
||||
|
|
@ -67,6 +69,8 @@ func attachChannels(lp *Loadpoint, uiChan chan util.Param, pushChan chan push.Ev
|
|||
}
|
||||
|
||||
func attachListeners(t *testing.T, lp *Loadpoint) {
|
||||
t.Helper()
|
||||
|
||||
Voltage = 230 // V
|
||||
|
||||
if charger, ok := lp.charger.(*api.MockCharger); ok && charger != nil {
|
||||
|
|
@ -421,7 +425,7 @@ func TestDisableAndEnableAtTargetSoc(t *testing.T) {
|
|||
attachListeners(t, lp)
|
||||
|
||||
lp.enabled = true
|
||||
lp.chargeCurrent = float64(minA)
|
||||
lp.chargeCurrent = minA
|
||||
lp.status = api.StatusC
|
||||
|
||||
t.Log("charging below soc target")
|
||||
|
|
@ -487,7 +491,7 @@ func TestSetModeAndSocAtDisconnect(t *testing.T) {
|
|||
attachListeners(t, lp)
|
||||
|
||||
lp.enabled = true
|
||||
lp.chargeCurrent = float64(minA)
|
||||
lp.chargeCurrent = minA
|
||||
lp.mode = api.ModeNow
|
||||
|
||||
t.Log("charging at min")
|
||||
|
|
@ -512,6 +516,8 @@ func TestSetModeAndSocAtDisconnect(t *testing.T) {
|
|||
|
||||
// cacheExpecter can be used to verify asynchronously written values from cache
|
||||
func cacheExpecter(t *testing.T, lp *Loadpoint) (*util.Cache, func(key string, val interface{})) {
|
||||
t.Helper()
|
||||
|
||||
// attach cache for verifying values
|
||||
paramC := make(chan util.Param)
|
||||
lp.uiChan = paramC
|
||||
|
|
@ -554,7 +560,7 @@ func TestChargedEnergyAtDisconnect(t *testing.T) {
|
|||
attachListeners(t, lp)
|
||||
|
||||
lp.enabled = true
|
||||
lp.chargeCurrent = float64(maxA)
|
||||
lp.chargeCurrent = maxA
|
||||
lp.mode = api.ModeNow
|
||||
|
||||
// attach cache for verifying values
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func rates(prices []float64, start time.Time, slotDuration time.Duration) api.Rates {
|
||||
|
|
@ -43,13 +44,13 @@ func TestPlan(t *testing.T) {
|
|||
}
|
||||
|
||||
rates, err := trf.Rates()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
slices.SortStableFunc(rates, sortByCost)
|
||||
|
||||
{
|
||||
plan := p.plan(rates, time.Hour, clock.Now())
|
||||
assert.Equal(t, 0, len(plan))
|
||||
assert.Empty(t, plan)
|
||||
}
|
||||
|
||||
tc := []struct {
|
||||
|
|
@ -81,7 +82,7 @@ func TestPlan(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"plan (30)30-0-60-0-0-0",
|
||||
time.Duration(90 * time.Minute),
|
||||
90 * time.Minute,
|
||||
clock.Now(),
|
||||
clock.Now().Add(6 * time.Hour),
|
||||
clock.Now().Add(30 * time.Minute),
|
||||
|
|
@ -105,7 +106,7 @@ func TestPlan(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"plan (30)30-0-60-0-0-0",
|
||||
time.Duration(90 * time.Minute),
|
||||
90 * time.Minute,
|
||||
clock.Now().Add(30 * time.Minute),
|
||||
clock.Now().Add(6 * time.Hour),
|
||||
clock.Now().Add(30 * time.Minute),
|
||||
|
|
@ -133,12 +134,12 @@ func TestNilTariff(t *testing.T) {
|
|||
}
|
||||
|
||||
plan, err := p.Plan(time.Hour, clock.Now().Add(30*time.Minute))
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should start past start time")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, SlotAt(clock.Now(), plan).IsEmpty(), "should start past start time")
|
||||
|
||||
plan, err = p.Plan(time.Hour, clock.Now().Add(-30*time.Minute))
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
}
|
||||
|
||||
func TestFlatTariffTargetInThePast(t *testing.T) {
|
||||
|
|
@ -155,12 +156,12 @@ func TestFlatTariffTargetInThePast(t *testing.T) {
|
|||
}
|
||||
|
||||
plan, err := p.Plan(time.Hour, clock.Now().Add(30*time.Minute))
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should start past start time")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, SlotAt(clock.Now(), plan).IsEmpty(), "should start past start time")
|
||||
|
||||
plan, err = p.Plan(time.Hour, clock.Now().Add(-30*time.Minute))
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
}
|
||||
|
||||
func TestFlatTariffLongSlots(t *testing.T) {
|
||||
|
|
@ -181,13 +182,13 @@ func TestFlatTariffLongSlots(t *testing.T) {
|
|||
|
||||
// expect 00:00-01:00 UTC
|
||||
plan, err := p.Plan(time.Hour, clock.Now().Add(2*time.Hour))
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, api.Rate{Start: clock.Now(), End: clock.Now().Add(time.Hour)}, SlotAt(clock.Now(), plan))
|
||||
assert.Equal(t, api.Rate{}, SlotAt(clock.Now().Add(time.Hour), plan))
|
||||
|
||||
// expect 00:00-01:00 UTC
|
||||
plan, err = p.Plan(time.Hour, clock.Now().Add(time.Hour))
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, api.Rate{Start: clock.Now(), End: clock.Now().Add(time.Hour)}, SlotAt(clock.Now(), plan))
|
||||
}
|
||||
|
||||
|
|
@ -205,11 +206,11 @@ func TestTargetAfterKnownPrices(t *testing.T) {
|
|||
}
|
||||
|
||||
plan, err := p.Plan(40*time.Minute, clock.Now().Add(2*time.Hour)) // charge efficiency does not allow to test with 1h
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should not start if car can be charged completely after known prices ")
|
||||
|
||||
plan, err = p.Plan(2*time.Hour, clock.Now().Add(2*time.Hour))
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should start if car can not be charged completely after known prices ")
|
||||
}
|
||||
|
||||
|
|
@ -227,10 +228,10 @@ func TestChargeAfterTargetTime(t *testing.T) {
|
|||
}
|
||||
|
||||
plan, err := p.Plan(time.Hour, clock.Now())
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
|
||||
plan, err = p.Plan(time.Hour, clock.Now().Add(-time.Hour))
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, !SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, SlotAt(clock.Now(), plan).IsEmpty(), "should not start past target time")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDetermineBatteryMode(t *testing.T) {
|
||||
|
|
@ -49,7 +50,6 @@ func TestDetermineBatteryMode(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUpdateBatteryMode(t *testing.T) {
|
||||
|
||||
expBatMode := api.BatteryHold
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
|
@ -70,6 +70,6 @@ func TestUpdateBatteryMode(t *testing.T) {
|
|||
}
|
||||
|
||||
err := s.updateBatteryMode(expBatMode)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expBatMode, s.GetBatteryMode())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,51 +37,81 @@ func TestGreenShare(t *testing.T) {
|
|||
grid, pv, battery, home, lp float64
|
||||
greenShareTotal, greenShareHome, greenShareLoadpoints float64
|
||||
}{
|
||||
{"half grid, half pv, green home",
|
||||
{
|
||||
"half grid, half pv, green home",
|
||||
1000, 1000, 0, 1000, 1000,
|
||||
0.5, 1, 0},
|
||||
{"half grid, half pv, no home",
|
||||
0.5, 1, 0,
|
||||
},
|
||||
{
|
||||
"half grid, half pv, no home",
|
||||
1000, 1000, 0, 0, 2000,
|
||||
0.5, 1, 0.5},
|
||||
{"half grid, half pv, no lp",
|
||||
0.5, 1, 0.5,
|
||||
},
|
||||
{
|
||||
"half grid, half pv, no lp",
|
||||
2500, 2500, 0, 5000, 0,
|
||||
0.5, 0.5, 0},
|
||||
{"full pv",
|
||||
0.5, 0.5, 0,
|
||||
},
|
||||
{
|
||||
"full pv",
|
||||
0, 5000, 0, 1000, 4000,
|
||||
1, 1, 1},
|
||||
{"full grid",
|
||||
1, 1, 1,
|
||||
},
|
||||
{
|
||||
"full grid",
|
||||
5000, 0, 0, 1000, 4000,
|
||||
0, 0, 0},
|
||||
{"half grid, half battery, green home",
|
||||
0, 0, 0,
|
||||
},
|
||||
{
|
||||
"half grid, half battery, green home",
|
||||
1000, 0, 1000, 1000, 1000,
|
||||
0.5, 1, 0},
|
||||
{"half grid, half battery, no home",
|
||||
0.5, 1, 0,
|
||||
},
|
||||
{
|
||||
"half grid, half battery, no home",
|
||||
1000, 0, 1000, 0, 2000,
|
||||
0.5, 1, 0.5},
|
||||
{"half grid, half battery, no lp",
|
||||
0.5, 1, 0.5,
|
||||
},
|
||||
{
|
||||
"half grid, half battery, no lp",
|
||||
1000, 0, 1000, 2000, 0,
|
||||
0.5, 0.5, 0},
|
||||
{"full pv, pv export",
|
||||
0.5, 0.5, 0,
|
||||
},
|
||||
{
|
||||
"full pv, pv export",
|
||||
-5000, 10000, 0, 1000, 4000,
|
||||
1, 1, 1},
|
||||
{"full pv, pv export, no lp",
|
||||
1, 1, 1,
|
||||
},
|
||||
{
|
||||
"full pv, pv export, no lp",
|
||||
-5000, 10000, 0, 5000, 0,
|
||||
1, 1, 1},
|
||||
{"full pv, pv export, battery charge",
|
||||
1, 1, 1,
|
||||
},
|
||||
{
|
||||
"full pv, pv export, battery charge",
|
||||
-2500, 10000, -2500, 1000, 4000,
|
||||
1, 1, 1},
|
||||
{"full grid, battery charge",
|
||||
1, 1, 1,
|
||||
},
|
||||
{
|
||||
"full grid, battery charge",
|
||||
3000, 0, -1000, 1000, 1000,
|
||||
0, 0, 0},
|
||||
{"full grid, battery charge, no lp",
|
||||
0, 0, 0,
|
||||
},
|
||||
{
|
||||
"full grid, battery charge, no lp",
|
||||
2000, 0, -1000, 1000, 0,
|
||||
0, 0, 0},
|
||||
{"half grid, half pv, battery charge, no lp",
|
||||
0, 0, 0,
|
||||
},
|
||||
{
|
||||
"half grid, half pv, battery charge, no lp",
|
||||
1000, 1000, -1000, 1000, 0,
|
||||
1, 1, 0},
|
||||
{"half grid, half pv, battery charge, home, lp",
|
||||
1, 1, 0,
|
||||
},
|
||||
{
|
||||
"half grid, half pv, battery charge, home, lp",
|
||||
1000, 1000, -1000, 500, 500,
|
||||
1, 1, 1},
|
||||
1, 1, 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func (s *Estimator) Reset() {
|
|||
s.prevSoc = 0
|
||||
s.prevChargedEnergy = 0
|
||||
s.initialSoc = 0
|
||||
s.capacity = float64(s.vehicle.Capacity()) * 1e3 // cache to simplify debugging
|
||||
s.capacity = s.vehicle.Capacity() * 1e3 // cache to simplify debugging
|
||||
s.virtualCapacity = s.capacity / ChargeEfficiency // initial capacity taking efficiency into account
|
||||
s.energyPerSocStep = s.virtualCapacity / 100
|
||||
s.minChargePower = 1000 // default 1 kW
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@ func TestTimer(t *testing.T) {
|
|||
// start
|
||||
at.Start()
|
||||
clck.Add(10 * time.Second)
|
||||
require.Equal(t, at.Expired(), false)
|
||||
require.False(t, at.Expired())
|
||||
|
||||
// wait another 20 sec to expire the timer - this will reset the timer as well
|
||||
clck.Add(wakeupTimeout + 10*time.Second)
|
||||
require.Equal(t, at.Expired(), true)
|
||||
require.True(t, at.Expired())
|
||||
|
||||
// start
|
||||
at.Start()
|
||||
clck.Add(time.Minute)
|
||||
require.Equal(t, at.Expired(), true)
|
||||
require.True(t, at.Expired())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/evcc-io/evcc/hems/ocpp/profile"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/machine"
|
||||
|
||||
ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6"
|
||||
ocppcore "github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
|
||||
"github.com/lorenzodonini/ocpp-go/ws"
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ func (c *API) updateValues() error {
|
|||
req, err := request.New(http.MethodPost, uri, strings.NewReader(data), map[string]string{
|
||||
"Content-Type": "text/plain",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Test MethodResponse response
|
||||
func TestUnmarshalMethodResponse(t *testing.T) {
|
||||
|
||||
{
|
||||
// BidCos-RF (Port 2001) getParamset measure-channel response test
|
||||
var res MethodResponse
|
||||
|
||||
xmlstr := `<?xml version="1.0" encoding="iso-8859-1"?><methodResponse><params><param><value><struct><member><name>IEC_ENERGY_COUNTER</name><value><double>689.586500</double></value></member><member><name>IEC_POWER</name><value><double>166.390000</double></value></member></struct></value></param></params></methodResponse>`
|
||||
assert.NoError(t, xml.Unmarshal([]byte(strings.Replace(string(xmlstr), "iso-8859-1", "UTF-8", 1)), &res))
|
||||
require.NoError(t, xml.Unmarshal([]byte(strings.Replace(xmlstr, "iso-8859-1", "UTF-8", 1)), &res))
|
||||
|
||||
assert.Equal(t, "IEC_ENERGY_COUNTER", res.Member[0].Name)
|
||||
assert.Equal(t, float64(689.586500), res.Member[0].Value.CCUFloat)
|
||||
|
|
@ -27,7 +27,7 @@ func TestUnmarshalMethodResponse(t *testing.T) {
|
|||
var res MethodResponse
|
||||
|
||||
xmlstr := `<?xml version="1.0" encoding="ISO-8859-1"?><methodResponse><params><param><value><struct><member><name>VOLTAGE</name><value><double>230.6</double></value></member><member><name>POWER_STATUS</name><value><i4>0</i4></value></member><member><name>ENERGY_COUNTER</name><value><double>10888.7</double></value></member><member><name>CURRENT_STATUS</name><value><i4>0</i4></value></member><member><name>FREQUENCY</name><value><double>49.97</double></value></member><member><name>ENERGY_COUNTER_OVERFLOW</name><value><boolean>0</boolean></value></member><member><name>POWER</name><value><double>0.05</double></value></member><member><name>VOLTAGE_STATUS</name><value><i4>0</i4></value></member><member><name>CURRENT</name><value><double>0.0</double></value></member><member><name>FREQUENCY_STATUS</name><value><i4>0</i4></value></member></struct></value></param></params></methodResponse>`
|
||||
assert.NoError(t, xml.Unmarshal([]byte(strings.Replace(string(xmlstr), "ISO-8859-1", "UTF-8", 1)), &res))
|
||||
require.NoError(t, xml.Unmarshal([]byte(strings.Replace(xmlstr, "ISO-8859-1", "UTF-8", 1)), &res))
|
||||
|
||||
assert.Equal(t, "ENERGY_COUNTER", res.Member[2].Name)
|
||||
assert.Equal(t, float64(10888.7), res.Member[2].Value.CCUFloat)
|
||||
|
|
@ -40,10 +40,10 @@ func TestUnmarshalMethodResponse(t *testing.T) {
|
|||
var res MethodResponse
|
||||
|
||||
xmlstr := `<?xml version="1.0" encoding="ISO-8859-1"?><methodResponse><params><param><value><struct><member><name>SECTION_STATUS</name><value><i4>0</i4></value></member><member><name>PROCESS</name><value><i4>0</i4></value></member><member><name>STATE</name><value><boolean>1</boolean></value></member><member><name>SECTION</name><value><i4>2</i4></value></member></struct></value></param></params></methodResponse>`
|
||||
assert.NoError(t, xml.Unmarshal([]byte(strings.Replace(string(xmlstr), "ISO-8859-1", "UTF-8", 1)), &res))
|
||||
require.NoError(t, xml.Unmarshal([]byte(strings.Replace(xmlstr, "ISO-8859-1", "UTF-8", 1)), &res))
|
||||
|
||||
assert.Equal(t, "STATE", res.Member[2].Name)
|
||||
assert.Equal(t, true, res.Member[2].Value.CCUBool)
|
||||
assert.True(t, res.Member[2].Value.CCUBool)
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -51,12 +51,11 @@ func TestUnmarshalMethodResponse(t *testing.T) {
|
|||
var res MethodResponse
|
||||
|
||||
xmlstr := `<?xml version="1.0" encoding="ISO-8859-1"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><i4>-2</i4></value></member><member><name>faultString</name><value>Invalid device</value></member></struct></value></fault></methodResponse>`
|
||||
assert.NoError(t, xml.Unmarshal([]byte(strings.Replace(string(xmlstr), "ISO-8859-1", "UTF-8", 1)), &res))
|
||||
require.NoError(t, xml.Unmarshal([]byte(strings.Replace(xmlstr, "ISO-8859-1", "UTF-8", 1)), &res))
|
||||
|
||||
assert.Equal(t, "faultCode", res.Fault[0].Name)
|
||||
assert.Equal(t, int64(-2), res.Fault[0].Value.CCUInt)
|
||||
assert.Equal(t, "faultString", res.Fault[1].Name)
|
||||
assert.Equal(t, "Invalid device", res.Fault[1].Value.CCUString)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Test ApiResponse
|
||||
|
|
@ -13,7 +14,7 @@ func TestUnmarshalApiResponse(t *testing.T) {
|
|||
var res ApiResponse
|
||||
|
||||
jsonstr := `{"product_type": "HWE-SKT","product_name": "P1 Meter","serial": "3c39e7aabbcc","firmware_version": "2.11","api_version": "v1"}`
|
||||
assert.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
|
||||
assert.Equal(t, "HWE-SKT", res.ProductType)
|
||||
assert.Equal(t, "v1", res.ApiVersion)
|
||||
|
|
@ -26,9 +27,9 @@ func TestUnmarshalStateResponse(t *testing.T) {
|
|||
var res StateResponse
|
||||
|
||||
jsonstr := `{"power_on": true,"switch_lock": false,"brightness": 255}`
|
||||
assert.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
|
||||
assert.Equal(t, true, res.PowerOn)
|
||||
assert.True(t, res.PowerOn)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +39,7 @@ func TestUnmarshalDataResponse(t *testing.T) {
|
|||
var res DataResponse
|
||||
|
||||
jsonstr := `{"wifi_ssid": "My Wi-Fi","wifi_strength": 100,"total_power_import_t1_kwh": 30.511,"total_power_export_t1_kwh": 85.951,"active_power_w": 543,"active_power_l1_w": 676}`
|
||||
assert.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
|
||||
assert.Equal(t, float64(30.511), res.TotalPowerImportT1kWh+res.TotalPowerImportT2kWh+res.TotalPowerImportT3kWh+res.TotalPowerImportT4kWh)
|
||||
assert.Equal(t, float64(543), res.ActivePowerW)
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ func NewPowerWall(uri, usage, user, password string, cache time.Duration, refres
|
|||
}
|
||||
|
||||
batteryCapacity = func() float64 {
|
||||
return float64(res.NominalFullPackEnergy) / 1e3
|
||||
return res.NominalFullPackEnergy / 1e3
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +212,7 @@ func (m *PowerWall) batterySoc() (float64, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
return float64(res.Percentage), err
|
||||
return res.Percentage, err
|
||||
}
|
||||
|
||||
// decorate soc
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
||||
"github.com/mlnoga/rct"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ func (sh *Switch) TotalEnergy() (float64, error) {
|
|||
func gen1Energy(devicetype string, energy float64) float64 {
|
||||
// Gen 1 Shelly EM devices are providing Watt hours, Gen 1 Shelly PM devices are providing Watt minutes
|
||||
if !strings.Contains(devicetype, "EM") {
|
||||
energy = energy / 60
|
||||
energy /= 60
|
||||
}
|
||||
return energy
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Test Gen1StatusResponse response
|
||||
|
|
@ -14,7 +15,7 @@ func TestUnmarshalGen1StatusResponse(t *testing.T) {
|
|||
var res Gen1StatusResponse
|
||||
|
||||
jsonstr := `{"wifi_sta":{"connected":true,"ssid":"XXXX-WLAN","ip":"192.168.178.XXX","rssi":-54},"cloud":{"enabled":false,"connected":false},"mqtt":{"connected":false},"time":"17:59","unixtime":1676134770,"serial":2437,"has_update":true,"mac":"84CCA8XXXXXXX","cfg_changed_cnt":1,"actions_stats":{"skipped":0},"relays":[{"ison":false,"has_timer":false,"timer_started":0,"timer_duration":0,"timer_remaining":0,"overpower":false,"source":"http"}],"meters":[{"power":4711.12,"overpower":0.00,"is_valid":true,"timestamp":1676138370,"counters":[0.000, 0.000, 0.000],"total":6472513}],"inputs":[{"input":0,"event":"","event_cnt":0}],"temperature":16.79,"overtemperature":false,"tmp":{"tC":16.79,"tF":62.22, "is_valid":true},"temperature_status":"Normal","ext_sensors":{},"ext_temperature":{},"ext_humidity":{},"update":{"status":"pending","has_update":true,"new_version":"20221108-153925/v1.12.1-1PM-fix-g2821131","old_version":"20220209-094317/v1.11.8-g8c7bb8d"},"ram_total":50456,"ram_free":37056,"fs_size":233681,"fs_free":149094,"uptime":17284290}`
|
||||
assert.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
|
||||
assert.Equal(t, 107875.21666666666, gen1Energy("SHSW-PM", res.Meters[0].Total))
|
||||
assert.Equal(t, 4711.12, res.Meters[0].Power)
|
||||
|
|
@ -25,7 +26,7 @@ func TestUnmarshalGen1StatusResponse(t *testing.T) {
|
|||
var res Gen1StatusResponse
|
||||
|
||||
jsonstr := `{"wifi_sta":{"connected":true,"ssid":"XXXX-WLAN","ip":"192.168.178.XXX","rssi":-57},"cloud":{"enabled":false,"connected":false},"mqtt":{"connected":false},"time":"19:25","unixtime":1676139913,"serial":959,"has_update":true,"mac":"E8DB8XXXXXX","cfg_changed_cnt":1,"actions_stats":{"skipped":0},"relays":[{"ison":false,"has_timer":false,"timer_started":0,"timer_duration":0,"timer_remaining":0,"source":"timer"}],"meters":[{"power":81.5,"is_valid":true}],"inputs":[{"input":0,"event":"","event_cnt":0}],"ext_sensors":{},"ext_temperature":{},"ext_humidity":{},"update":{"status":"pending","has_update":true,"new_version":"20221027-091427/v1.12.1-ga9117d3","old_version":"20211109-124958/v1.11.7-g682a0db"},"ram_total":50880,"ram_free":38796,"fs_size":233681,"fs_free":151102,"uptime":20319391}`
|
||||
assert.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
|
||||
assert.Equal(t, 0.0, gen1Energy("SHSW-1", res.Meters[0].Total))
|
||||
assert.Equal(t, 81.5, res.Meters[0].Power)
|
||||
|
|
@ -36,7 +37,7 @@ func TestUnmarshalGen1StatusResponse(t *testing.T) {
|
|||
var res Gen1StatusResponse
|
||||
|
||||
jsonstr := `{"wifi_sta":{"connected":true,"ssid":"XXXX","ip":"192.168.178.XXX","rssi":-55},"cloud":{"enabled":false,"connected":false},"mqtt":{"connected":false},"time":"11:16","unixtime":1676110566,"serial":21580,"has_update":false,"mac":"C45BXXXXX","cfg_changed_cnt":0,"actions_stats":{"skipped":0},"relays":[{"ison":false,"has_timer":false,"timer_started":0,"timer_duration":0,"timer_remaining":0,"overpower":false,"is_valid":true,"source":"input"}],"emeters":[{"power":-620.34,"reactive":714.48,"pf":-0.66,"voltage":235.68,"is_valid":true,"total":401472.9,"total_returned":653673.7},{"power":0.00,"reactive":0.00,"pf":0.00,"voltage":235.68,"is_valid":true,"total":173411.3,"total_returned":294.2}],"update":{"status":"idle","has_update":false,"new_version":"20221027-105518/v1.12.1-ga9117d3","old_version":"20221027-105518/v1.12.1-ga9117d3"},"ram_total":51072,"ram_free":35660,"fs_size":233681,"fs_free":156373,"uptime":2226140}`
|
||||
assert.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
|
||||
assert.Equal(t, 401472.9, gen1Energy("SHEM", res.EMeters[0].Total))
|
||||
assert.Equal(t, -620.34, res.EMeters[0].Power)
|
||||
|
|
@ -49,7 +50,7 @@ func TestUnmarshalGen2StatusResponse(t *testing.T) {
|
|||
var res Gen2StatusResponse
|
||||
|
||||
jsonstr := `{"ble":{},"cloud":{"connected":true},"eth":{"ip":null},"input:0":{"id":0,"state":false},"input:1":{"id":1,"state":false},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP", "output":false, "apower":47.11, "voltage":232.0, "current":0.000, "pf":0.00, "aenergy":{"total":5.125,"by_minute":[0.000,0.000,0.000],"minute_ts":1675718520},"temperature":{"tC":25.3, "tF":77.5}},"sys":{"mac":"30C6F78BB4D8","restart_required":false,"time":"22:22","unixtime":1675718522,"uptime":45070,"ram_size":234204,"ram_free":137716,"fs_size":524288,"fs_free":172032,"cfg_rev":13,"kvs_rev":1,"schedule_rev":0,"webhook_rev":0,"available_updates":{"beta":{"version":"0.13.0-beta3"}}},"wifi":{"sta_ip":"192.168.178.64","status":"got ip","ssid":"***","rssi":-62},"ws":{"connected":false}}`
|
||||
assert.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
|
||||
|
||||
assert.Equal(t, 5.125, res.Switch0.Aenergy.Total)
|
||||
assert.Equal(t, 47.11, res.Switch0.Apower)
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func (c *Connection) ChargedEnergy() (float64, error) {
|
|||
}
|
||||
|
||||
if int64(resp.TodayEnergy) > c.lasttodayenergy {
|
||||
c.energy = c.energy + (int64(resp.TodayEnergy) - c.lasttodayenergy)
|
||||
c.energy += (int64(resp.TodayEnergy) - c.lasttodayenergy)
|
||||
}
|
||||
c.lasttodayenergy = int64(resp.TodayEnergy)
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ func (c *Connection) RelayExists() error {
|
|||
// Enable implements the api.Charger interface
|
||||
func (c *Connection) Enable(enable bool) error {
|
||||
for _, channel := range c.channels {
|
||||
|
||||
cmd := fmt.Sprintf("Power%d off", channel)
|
||||
if enable {
|
||||
cmd = fmt.Sprintf("Power%d on", channel)
|
||||
|
|
@ -191,7 +190,6 @@ func (c *Connection) Enabled() (bool, error) {
|
|||
enabled = strings.ToUpper(res.StatusSTS.Power8) == "ON"
|
||||
default:
|
||||
enabled = strings.ToUpper(res.StatusSTS.Power) == "ON" || strings.ToUpper(res.StatusSTS.Power1) == "ON"
|
||||
|
||||
}
|
||||
}
|
||||
return enabled, nil
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ var acceptable = []string{
|
|||
|
||||
func TestTemplates(t *testing.T) {
|
||||
templates.TestClass(t, templates.Meter, func(t *testing.T, values map[string]any) {
|
||||
t.Helper()
|
||||
|
||||
if _, err := NewFromConfig("template", values); err != nil && !test.Acceptable(err, acceptable) {
|
||||
t.Log(values)
|
||||
t.Error(err)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func (d *Connection) ExecCmd(cmd string, res interface{}) error {
|
|||
buf := bytes.NewBuffer([]byte{0, 0, 0, 0})
|
||||
var key byte = 171 // initialization vector
|
||||
for i := 0; i < len(cmd); i++ {
|
||||
key = key ^ cmd[i]
|
||||
key ^= cmd[i]
|
||||
_ = buf.WriteByte(key)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func process(filepath string) error {
|
|||
fmt.Fprintln(out, sc.Text())
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filepath, []byte(out.String()), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath, []byte(out.String()), 0o644); err != nil {
|
||||
return fmt.Errorf("%s: %v", filepath, err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ func TestCachedGetter(t *testing.T) {
|
|||
expect := func(s struct {
|
||||
f float64
|
||||
e error
|
||||
}) {
|
||||
},
|
||||
) {
|
||||
f, e := c.Get()
|
||||
if f != s.f || e != s.e {
|
||||
t.Errorf("unexpected cache value: %f, %v\n", f, e)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ func RegisteredClient(log *util.Logger, broker, user, password, clientID string,
|
|||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
client, err := registry.Get(key)
|
||||
|
||||
if err != nil {
|
||||
if clientID == "" {
|
||||
clientID = ClientID()
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func (h *msgHandler) stringGetter() (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
return string(v), nil
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (h *msgHandler) boolGetter() (bool, error) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ func TestRegexDefault(t *testing.T) {
|
|||
|
||||
func TestJq(t *testing.T) {
|
||||
for _, uuid := range []string{"a8232ee0-a4ab-11ec-8d36-211f6b082dc8", "08232ee0-a4ab-11ec-8d36-211f6b082dc8"} {
|
||||
|
||||
p, err := new(Pipeline).WithJq(fmt.Sprintf(`.data[] | select(.uuid=="%s") | .tuples[0][1]`, uuid))
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
v := "foo"
|
||||
SetString("string", v)
|
||||
res, err := String("string")
|
||||
assert.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, v, res)
|
||||
}
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ func TestInt(t *testing.T) {
|
|||
v := int64(math.MaxInt64)
|
||||
SetInt("int64", v)
|
||||
res, err := Int("int64")
|
||||
assert.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, v, res)
|
||||
}
|
||||
|
||||
|
|
@ -27,6 +28,6 @@ func TestFloat(t *testing.T) {
|
|||
v := 3.141
|
||||
SetFloat("float64", v)
|
||||
res, err := Float("float64")
|
||||
assert.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, v, res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func (w *influxWriter) WritePoint(p *write.Point) {
|
|||
}
|
||||
|
||||
func (w *influxWriter) finish() {
|
||||
assert.Equal(w.t, len(w.p), w.idx, "not enough points")
|
||||
assert.Len(w.t, w.p, w.idx, "not enough points")
|
||||
}
|
||||
|
||||
func TestInfluxTypes(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -12,23 +12,24 @@ import (
|
|||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestConcurrentRead(t *testing.T) {
|
||||
l, err := net.Listen("tcp", "localhost:0")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
defer l.Close()
|
||||
|
||||
srv, _ := mbserver.New(&echoHandler{
|
||||
id: 0,
|
||||
RequestHandler: new(mbserver.DummyHandler),
|
||||
})
|
||||
assert.NoError(t, srv.Start(l))
|
||||
require.NoError(t, srv.Start(l))
|
||||
defer func() { _ = srv.Stop() }()
|
||||
|
||||
// client
|
||||
conn, err := modbus.NewConnection(l.Addr().String(), "", "", 0, modbus.Tcp, 1)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
|
|
@ -41,7 +42,7 @@ func TestConcurrentRead(t *testing.T) {
|
|||
qty := uint16(rand.Int31n(32) + 1)
|
||||
|
||||
b, err := conn.ReadInputRegistersWithSlave(uint8(id), addr, qty)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err == nil {
|
||||
for u := uint16(0); u < qty; u++ {
|
||||
|
|
@ -62,56 +63,56 @@ func TestConcurrentRead(t *testing.T) {
|
|||
func TestReadCoils(t *testing.T) {
|
||||
// downstream server
|
||||
l, err := net.Listen("tcp", "localhost:0")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
defer l.Close()
|
||||
|
||||
srv, _ := mbserver.New(&echoHandler{
|
||||
id: 0,
|
||||
RequestHandler: new(mbserver.DummyHandler),
|
||||
})
|
||||
assert.NoError(t, srv.Start(l))
|
||||
require.NoError(t, srv.Start(l))
|
||||
defer func() { _ = srv.Stop() }()
|
||||
|
||||
// proxy server
|
||||
pl, err := net.Listen("tcp", "localhost:0")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
defer pl.Close()
|
||||
|
||||
downstreamConn, err := modbus.NewConnection(l.Addr().String(), "", "", 0, modbus.Tcp, 1)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
proxy, _ := mbserver.New(&handler{
|
||||
log: util.NewLogger("foo"),
|
||||
conn: downstreamConn,
|
||||
})
|
||||
assert.NoError(t, proxy.Start(pl))
|
||||
require.NoError(t, proxy.Start(pl))
|
||||
defer func() { _ = proxy.Stop() }()
|
||||
|
||||
// test client
|
||||
{
|
||||
conn, err := modbus.NewConnection(pl.Addr().String(), "", "", 0, modbus.Tcp, 1)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
{ // read
|
||||
b, err := conn.ReadCoilsWithSlave(1, 1, 1)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{0x01}, b)
|
||||
|
||||
b, err = conn.ReadCoilsWithSlave(1, 1, 2)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{0x03}, b)
|
||||
|
||||
b, err = conn.ReadCoilsWithSlave(1, 1, 9)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{0xFF, 0x01}, b)
|
||||
}
|
||||
{ // write
|
||||
b, err := conn.WriteSingleCoilWithSlave(1, 1, 0xFF00)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{0xFF, 0x00}, b)
|
||||
|
||||
b, err = conn.WriteMultipleCoilsWithSlave(1, 1, 9, []byte{0xFF, 0x01})
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{0x00, 0x09}, b)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error {
|
|||
var err error
|
||||
|
||||
if err == nil {
|
||||
err = m.Handler.ListenSetter(m.root+"/site/prioritySoc", func(payload string) error {
|
||||
err = m.Handler.ListenSetter(topic+"/site/prioritySoc", func(payload string) error {
|
||||
val, err := parseFloat(payload)
|
||||
if err == nil {
|
||||
err = site.SetPrioritySoc(val)
|
||||
|
|
@ -177,7 +177,7 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error {
|
|||
}
|
||||
|
||||
if err == nil {
|
||||
err = m.Handler.ListenSetter(m.root+"/site/bufferSoc", func(payload string) error {
|
||||
err = m.Handler.ListenSetter(topic+"/site/bufferSoc", func(payload string) error {
|
||||
val, err := parseFloat(payload)
|
||||
if err == nil {
|
||||
err = site.SetBufferSoc(val)
|
||||
|
|
@ -187,7 +187,7 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error {
|
|||
}
|
||||
|
||||
if err == nil {
|
||||
err = m.Handler.ListenSetter(m.root+"/site/bufferStartSoc", func(payload string) error {
|
||||
err = m.Handler.ListenSetter(topic+"/site/bufferStartSoc", func(payload string) error {
|
||||
val, err := parseFloat(payload)
|
||||
if err == nil {
|
||||
err = site.SetBufferStartSoc(val)
|
||||
|
|
@ -197,7 +197,7 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error {
|
|||
}
|
||||
|
||||
if err == nil {
|
||||
err = m.Handler.ListenSetter(m.root+"/site/residualPower", func(payload string) error {
|
||||
err = m.Handler.ListenSetter(topic+"/site/residualPower", func(payload string) error {
|
||||
val, err := parseFloat(payload)
|
||||
if err == nil {
|
||||
err = site.SetResidualPower(val)
|
||||
|
|
@ -207,7 +207,7 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error {
|
|||
}
|
||||
|
||||
if err == nil {
|
||||
err = m.Handler.ListenSetter(m.root+"/site/smartCostLimit", func(payload string) error {
|
||||
err = m.Handler.ListenSetter(topic+"/site/smartCostLimit", func(payload string) error {
|
||||
val, err := parseFloat(payload)
|
||||
if err == nil {
|
||||
err = site.SetSmartCostLimit(val)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
|
|
@ -27,7 +28,7 @@ func TestEncode(t *testing.T) {
|
|||
|
||||
for _, tc := range tc {
|
||||
out, err := encode(tc.in)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.out, out)
|
||||
}
|
||||
}
|
||||
|
|
@ -44,7 +45,7 @@ func TestEncodeSlice(t *testing.T) {
|
|||
|
||||
for _, tc := range tc {
|
||||
out, err := encodeSlice(tc.in)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.out, out)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ var zones = map[string][]string{
|
|||
"10YPT-REN------W": {"LFA|PT", "LFB|PT", "MBA|PT", "SCA|PT", "CTA|PT", "Portugal (PT)", "BZN|PT"},
|
||||
"10YRO-TEL------P": {"BZN|RO", "Romania (RO)", "CTA|RO", "SCA|RO", "MBA|RO", "LFB|RO", "LFA|RO"},
|
||||
"10YSE-1--------K": {"MBA|SE", "SCA|SE", "CTA|SE", "Sweden (SE)"},
|
||||
"10YSI-ELES-----O": {"Slovenia (SI)", "BZN|SI", "CTA|SI", "SCA|SI", "MBA|SI", "LFA|SI"},
|
||||
"10YSI-EELS-----O": {"Slovenia (SI)", "BZN|SI", "CTA|SI", "SCA|SI", "MBA|SI", "LFA|SI"},
|
||||
"10YSK-SEPS-----K": {"LFA|SK", "LFB|SK", "MBA|SK", "SCA|SK", "CTA|SK", "BZN|SK", "Slovakia (SK)"},
|
||||
"10YTR-TEIAS----W": {"Turkey (TR)", "BZN|TR", "CTA|TR", "SCA|TR", "MBA|TR", "LFB|TR", "LFA|TR"},
|
||||
"10YUA-WEPS-----0": {"LFA|UA-BEI", "LFB|UA-BEI", "MBA|UA-BEI", "SCA|UA-BEI", "CTA|UA-BEI", "BZN|UA-BEI"},
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ func ParseDays(s string) ([]Day, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, Day(from%7))
|
||||
res = append(res, from%7)
|
||||
|
||||
if len(fromto) == 2 {
|
||||
to, err := ParseDay(fromto[1])
|
||||
|
|
|
|||
|
|
@ -4,43 +4,44 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseDays(t *testing.T) {
|
||||
d, err := ParseDays(" sunday ")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Sunday}, d)
|
||||
|
||||
d, err = ParseDays("sun")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Sunday}, d)
|
||||
|
||||
d, err = ParseDays("so")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Sunday}, d)
|
||||
|
||||
d, err = ParseDays("0 ")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Sunday}, d)
|
||||
|
||||
d, err = ParseDays(" 7")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Sunday}, d)
|
||||
|
||||
d, err = ParseDays(" 6-7 ")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Saturday, Sunday}, d)
|
||||
|
||||
d, err = ParseDays("1- 7")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}, d)
|
||||
|
||||
_, err = ParseDays(" ")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}, d)
|
||||
|
||||
d, err = ParseDays("1, 3-7")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []Day{Monday, Wednesday, Thursday, Friday, Saturday, Sunday}, d)
|
||||
|
||||
_, err = ParseDays("-")
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseTimeRange(t *testing.T) {
|
||||
d, err := ParseTimeRanges(" 7:00 - 12:30 ")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []TimeRange{{HourMin{7, 0}, HourMin{12, 30}}}, d, "hour:min range")
|
||||
|
||||
d, err = ParseTimeRanges(" 8-10 ")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []TimeRange{{HourMin{8, 0}, HourMin{10, 0}}}, d, "hour range")
|
||||
|
||||
_, err = ParseTimeRanges("-1-10")
|
||||
|
|
@ -22,14 +23,14 @@ func TestParseTimeRange(t *testing.T) {
|
|||
assert.EqualError(t, err, "invalid time: 25", "<to> after midnight")
|
||||
|
||||
d, err = ParseTimeRanges("8-0")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []TimeRange{{HourMin{8, 0}, HourMin{0, 0}}}, d, "hour till midnight (0)")
|
||||
|
||||
_, err = ParseTimeRanges("10-8")
|
||||
assert.EqualError(t, err, "invalid time range: 10-8, <from> must be before <to>")
|
||||
|
||||
d, err = ParseTimeRanges("8-10, 20-22:30")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []TimeRange{
|
||||
{HourMin{8, 0}, HourMin{10, 0}},
|
||||
{HourMin{20, 0}, HourMin{22, 30}},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/evcc-io/evcc/tariff/fixed"
|
||||
"github.com/jinzhu/now"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFixed(t *testing.T) {
|
||||
|
|
@ -33,7 +34,7 @@ func TestFixed(t *testing.T) {
|
|||
}
|
||||
|
||||
rates, err := tf.Rates()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expect, rates)
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ func TestFixedSplitZones(t *testing.T) {
|
|||
{0.1, "0-5:30,21-0"},
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
tf := at.(*Fixed)
|
||||
tf.clock = clock.NewMock()
|
||||
|
|
@ -99,6 +100,6 @@ func TestFixedSplitZones(t *testing.T) {
|
|||
}
|
||||
|
||||
rates, err := tf.Rates()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expect, rates)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDecodeNil(t *testing.T) {
|
||||
|
|
@ -23,12 +24,12 @@ func TestDecodeNil(t *testing.T) {
|
|||
}
|
||||
|
||||
decoder, err := mapstructure.NewDecoder(decoderConfig)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = decoder.Decode(map[string]any{
|
||||
"user": nil,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, struct {
|
||||
User, Password string
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ func newLogger(area string, lp int) *Logger {
|
|||
|
||||
padded := area
|
||||
for len(padded) < LogAreaPadding {
|
||||
padded = padded + " "
|
||||
padded += " "
|
||||
}
|
||||
|
||||
level := LogLevelForArea(area)
|
||||
|
|
@ -188,10 +188,7 @@ func captureLogger(l *Logger) {
|
|||
}
|
||||
|
||||
func captureLogLevel(level string, lp int, l *log.Logger) {
|
||||
re, err := regexp.Compile(`^\[[a-zA-Z0-9-]+\s*\] \w+ .{19} `)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
re := regexp.MustCompile(`^\[[a-zA-Z0-9-]+\s*\] \w+ .{19} `)
|
||||
|
||||
ui := uiWriter{
|
||||
lp: lp,
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
var id string
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func decodeBool16(mask uint64) func(b []byte) float64 {
|
|||
return func(b []byte) float64 {
|
||||
u := binary.BigEndian.Uint16(b)
|
||||
if mask > 0 {
|
||||
u = u & uint16(mask)
|
||||
u &= uint16(mask)
|
||||
}
|
||||
if u > 0 {
|
||||
return 1
|
||||
|
|
|
|||
|
|
@ -390,7 +390,6 @@ func RegisterOperation(r Register) (rs485.Operation, error) {
|
|||
}
|
||||
|
||||
switch strings.ToLower(r.Decode) {
|
||||
|
||||
// 8 bit (coil)
|
||||
case "bool8":
|
||||
op.Transform = decodeBool8
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package templates
|
|||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ func (t *Template) RenderDocumentation(product Product, lang string) ([]byte, er
|
|||
case string:
|
||||
t.Params[index].Value = yamlQuote(v)
|
||||
case int:
|
||||
t.Params[index].Value = fmt.Sprintf("%d", v)
|
||||
t.Params[index].Value = strconv.Itoa(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import (
|
|||
|
||||
// test renders and instantiates plus yaml-parses the template per usage
|
||||
func test(t *testing.T, tmpl Template, values map[string]interface{}, cb func(values map[string]interface{})) {
|
||||
t.Helper()
|
||||
|
||||
b, _, err := tmpl.RenderResult(TemplateRenderModeInstance, values)
|
||||
if err != nil {
|
||||
t.Log(string(b))
|
||||
|
|
@ -32,6 +34,8 @@ func test(t *testing.T, tmpl Template, values map[string]interface{}, cb func(va
|
|||
}
|
||||
|
||||
func TestClass(t *testing.T, class Class, instantiate func(t *testing.T, values map[string]interface{})) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tmpl := range ByClass(class) {
|
||||
tmpl := tmpl
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
_ "embed"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
|
|
@ -230,7 +231,7 @@ func (t *Template) RenderProxyWithValues(values map[string]interface{}, lang str
|
|||
case string:
|
||||
t.Params[index].Value = yamlQuote(v)
|
||||
case int:
|
||||
t.Params[index].Value = fmt.Sprintf("%d", v)
|
||||
t.Params[index].Value = strconv.Itoa(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,9 +57,7 @@ func FuncMap(tmpl *template.Template) *template.Template {
|
|||
}
|
||||
return buf.String(), nil
|
||||
},
|
||||
"urlEncode": func(v string) string {
|
||||
return url.QueryEscape(v)
|
||||
},
|
||||
"urlEncode": url.QueryEscape,
|
||||
"toDuration": func(v string) time.Duration {
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ func TestYamlDecode(t *testing.T) {
|
|||
}
|
||||
|
||||
err := yaml.Unmarshal([]byte(input), &res)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, value, res.Value)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import (
|
|||
)
|
||||
|
||||
func SkipCI(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if os.Getenv("CI") != "" {
|
||||
t.Skip("Skipping testing in CI environment")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/evcc-io/evcc/provider"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
||||
"github.com/joeshaw/carwings"
|
||||
)
|
||||
|
||||
|
|
@ -111,7 +110,7 @@ func (v *CarWings) status() (carwings.BatteryStatus, error) {
|
|||
// api result is stale
|
||||
if v.refreshKey != "" {
|
||||
if err := v.refreshResult(); err != nil {
|
||||
return *new(carwings.BatteryStatus), err
|
||||
return carwings.BatteryStatus{}, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +119,7 @@ func (v *CarWings) status() (carwings.BatteryStatus, error) {
|
|||
if err == nil {
|
||||
if elapsed := time.Since(bs.Timestamp); elapsed > carwingsStatusExpiry {
|
||||
if err = v.refreshRequest(); err != nil {
|
||||
return *new(carwings.BatteryStatus), err
|
||||
return carwings.BatteryStatus{}, err
|
||||
}
|
||||
|
||||
err = api.ErrMustRetry
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ func (ct *TimeMillis) UnmarshalJSON(data []byte) error {
|
|||
|
||||
if err == nil {
|
||||
t := time.Unix(0, i*1e6)
|
||||
(*ct).Time = t
|
||||
ct.Time = t
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func (v *Identity) login() (*oauth.Token, error) {
|
|||
|
||||
var settings Settings
|
||||
|
||||
if err := json.Unmarshal([]byte(match[1]), &settings); err != nil {
|
||||
if err := json.Unmarshal(match[1], &settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ func (ct *Timestamp) UnmarshalJSON(data []byte) error {
|
|||
|
||||
t, err := time.Parse(TimeFormat, s)
|
||||
if err == nil {
|
||||
(*ct).Time = t
|
||||
ct.Time = t
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ func (v *Identity) Login(user, password string) error {
|
|||
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err == nil {
|
||||
if err = v.DoJSON(req, &res); err != nil && len(res.Errors) > 0 {
|
||||
err = fmt.Errorf("%s: %w", string(res.Errors[0].Key), err)
|
||||
err = fmt.Errorf("%s: %w", res.Errors[0].Key, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ func (v *Identity) Login(user, password string) error {
|
|||
req, err = request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err == nil {
|
||||
if err = v.DoJSON(req, &res); err != nil && len(res.Errors) > 0 {
|
||||
err = fmt.Errorf("%s: %w", string(res.Errors[0].Key), err)
|
||||
err = fmt.Errorf("%s: %w", res.Errors[0].Key, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ func (ct *Timestamp) UnmarshalJSON(data []byte) error {
|
|||
|
||||
t, err := time.Parse(timeFormat, s)
|
||||
if err == nil {
|
||||
(*ct).Time = t
|
||||
ct.Time = t
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package vehicle
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
|
|
@ -102,31 +103,31 @@ func (v *Ovms) loginToServer() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
func (v *Ovms) uri(path string) string {
|
||||
return fmt.Sprintf("https://%s/api/%s/%s", net.JoinHostPort(v.server, "6869"), path, v.vehicleId)
|
||||
}
|
||||
|
||||
func (v *Ovms) connectRequest() (ovmsConnectResponse, error) {
|
||||
uri := fmt.Sprintf("https://%s:6869/api/vehicle/%s", v.server, v.vehicleId)
|
||||
var res ovmsConnectResponse
|
||||
err := v.GetJSON(uri, &res)
|
||||
err := v.GetJSON(v.uri("vehicle"), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (v *Ovms) chargeRequest() (ovmsChargeResponse, error) {
|
||||
uri := fmt.Sprintf("https://%s:6869/api/charge/%s", v.server, v.vehicleId)
|
||||
var res ovmsChargeResponse
|
||||
err := v.GetJSON(uri, &res)
|
||||
err := v.GetJSON(v.uri("charge"), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (v *Ovms) statusRequest() (ovmsStatusResponse, error) {
|
||||
uri := fmt.Sprintf("https://%s:6869/api/status/%s", v.server, v.vehicleId)
|
||||
var res ovmsStatusResponse
|
||||
err := v.GetJSON(uri, &res)
|
||||
err := v.GetJSON(v.uri("status"), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (v *Ovms) locationRequest() (ovmsLocationResponse, error) {
|
||||
uri := fmt.Sprintf("https://%s:6869/api/location/%s", v.server, v.vehicleId)
|
||||
var res ovmsLocationResponse
|
||||
err := v.GetJSON(uri, &res)
|
||||
err := v.GetJSON(v.uri("location"), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ func newPSA(log *util.Logger, brand, realm, id, secret string, other map[string]
|
|||
return v.VIN
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ func (v *API) request_(uri string, body io.Reader) (Response, error) {
|
|||
|
||||
func (v *API) request(uri string, body io.Reader) (Response, error) {
|
||||
res, err := v.request_(uri, body)
|
||||
|
||||
// repeat auth if error
|
||||
if err != nil {
|
||||
if err = v.login(); err == nil {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ var _ api.Battery = (*Provider)(nil)
|
|||
// Soc implements the api.Vehicle interface
|
||||
func (v *Provider) Soc() (float64, error) {
|
||||
res, err := v.statusG()
|
||||
return float64(res.Engines.Primary.Level), err
|
||||
return res.Engines.Primary.Level, err
|
||||
}
|
||||
|
||||
var _ api.ChargeState = (*Provider)(nil)
|
||||
|
|
@ -89,7 +89,7 @@ var _ api.VehicleOdometer = (*Provider)(nil)
|
|||
// Odometer implements the api.VehicleOdometer interface
|
||||
func (v *Provider) Odometer() (float64, error) {
|
||||
res, err := v.statusG()
|
||||
return float64(res.Measurements.MileageKm), err
|
||||
return res.Measurements.MileageKm, err
|
||||
}
|
||||
|
||||
var _ api.VehicleClimater = (*Provider)(nil)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func (ct *TimeSecs) UnmarshalJSON(data []byte) error {
|
|||
|
||||
if err == nil {
|
||||
t := time.Unix(i, 0)
|
||||
(*ct).Time = t
|
||||
ct.Time = t
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ var acceptable = []string{
|
|||
|
||||
func TestTemplates(t *testing.T) {
|
||||
templates.TestClass(t, templates.Vehicle, func(t *testing.T, values map[string]any) {
|
||||
t.Helper()
|
||||
|
||||
if _, err := NewFromConfig("template", values); err != nil && !test.Acceptable(err, acceptable) {
|
||||
t.Log(values)
|
||||
t.Error(err)
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ func (ct *Timestamp) UnmarshalJSON(data []byte) error {
|
|||
|
||||
t, err := time.Parse(timeFormat, s)
|
||||
if err == nil {
|
||||
(*ct).Time = t
|
||||
ct.Time = t
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ func (ct *Timestamp) UnmarshalJSON(data []byte) error {
|
|||
|
||||
t, err := time.Parse(time.RFC3339, s)
|
||||
if err == nil {
|
||||
(*ct).Time = t
|
||||
ct.Time = t
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -133,12 +133,12 @@ func (t *TimedTemperature) UnmarshalJSON(data []byte) error {
|
|||
|
||||
err := json.Unmarshal(data, &temp)
|
||||
if err == nil {
|
||||
(*t).Timestamp = temp.Timestamp
|
||||
t.Timestamp = temp.Timestamp
|
||||
|
||||
if val, err := strconv.Atoi(string(temp.Content)); err == nil {
|
||||
(*t).Content = temp2Float(val)
|
||||
t.Content = temp2Float(val)
|
||||
} else {
|
||||
(*t).Content = math.NaN()
|
||||
t.Content = math.NaN()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue