Add ConnectIQ charger (#3622)
This commit is contained in:
parent
266071df51
commit
e16c52514d
3 changed files with 216 additions and 7 deletions
|
|
@ -95,6 +95,13 @@ func (wb *Blueprint) ChargedEnergy() (float64, error) {
|
||||||
return 0, api.ErrNotAvailable
|
return 0, api.ErrNotAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ api.MeterEnergy = (*Blueprint)(nil)
|
||||||
|
|
||||||
|
// TotalEnergy implements the api.MeterEnergy interface
|
||||||
|
func (wb *Blueprint) TotalEnergy() (float64, error) {
|
||||||
|
return 0, api.ErrNotAvailable
|
||||||
|
}
|
||||||
|
|
||||||
var _ api.MeterCurrent = (*Blueprint)(nil)
|
var _ api.MeterCurrent = (*Blueprint)(nil)
|
||||||
|
|
||||||
// Currents implements the api.MeterCurrent interface
|
// Currents implements the api.MeterCurrent interface
|
||||||
|
|
@ -109,13 +116,6 @@ func (wb *Blueprint) Identify() (string, error) {
|
||||||
return "", api.ErrNotAvailable
|
return "", api.ErrNotAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ api.MeterEnergy = (*Blueprint)(nil)
|
|
||||||
|
|
||||||
// TotalEnergy implements the api.MeterEnergy interface
|
|
||||||
func (wb *Blueprint) TotalEnergy() (float64, error) {
|
|
||||||
return 0, api.ErrNotAvailable
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ api.ChargePhases = (*Blueprint)(nil)
|
var _ api.ChargePhases = (*Blueprint)(nil)
|
||||||
|
|
||||||
// Phases1p3p implements the api.ChargePhases interface
|
// Phases1p3p implements the api.ChargePhases interface
|
||||||
|
|
|
||||||
185
charger/connectiq.go
Normal file
185
charger/connectiq.go
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
package charger
|
||||||
|
|
||||||
|
// LICENSE
|
||||||
|
|
||||||
|
// Copyright (c) 2019-2022 andig
|
||||||
|
|
||||||
|
// This module is NOT covered by the MIT license. All rights reserved.
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/evcc-io/evcc/api"
|
||||||
|
"github.com/evcc-io/evcc/charger/connectiq"
|
||||||
|
"github.com/evcc-io/evcc/provider"
|
||||||
|
"github.com/evcc-io/evcc/util"
|
||||||
|
"github.com/evcc-io/evcc/util/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConnectIq charger implementation
|
||||||
|
type ConnectIq struct {
|
||||||
|
*request.Helper
|
||||||
|
uri string
|
||||||
|
curr int64
|
||||||
|
meterG func() (connectiq.MeterStatus, error)
|
||||||
|
cache time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.Add("connectiq", NewConnectIqFromConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConnectIqFromConfig creates a ConnectIq charger from generic config
|
||||||
|
func NewConnectIqFromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||||
|
cc := struct {
|
||||||
|
URI string
|
||||||
|
Cache time.Duration
|
||||||
|
}{
|
||||||
|
Cache: time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := util.DecodeOther(other, &cc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewConnectIq(cc.URI, cc.Cache)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConnectIq creates ConnectIq charger
|
||||||
|
func NewConnectIq(uri string, cache time.Duration) (api.Charger, error) {
|
||||||
|
log := util.NewLogger("connectiq")
|
||||||
|
|
||||||
|
wb := &ConnectIq{
|
||||||
|
Helper: request.NewHelper(log),
|
||||||
|
uri: util.DefaultScheme(strings.TrimSuffix(uri, "/"), "http"),
|
||||||
|
curr: 6,
|
||||||
|
cache: cache,
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache meter readings
|
||||||
|
wb.meterG = provider.Cached(func() (connectiq.MeterStatus, error) {
|
||||||
|
var res connectiq.MeterStatus
|
||||||
|
uri := fmt.Sprintf("%s/meter/status", wb.uri)
|
||||||
|
err := wb.GetJSON(uri, &res)
|
||||||
|
return res, err
|
||||||
|
}, wb.cache)
|
||||||
|
|
||||||
|
return wb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wb *ConnectIq) status() (connectiq.ChargeStatus, error) {
|
||||||
|
var res connectiq.ChargeStatus
|
||||||
|
uri := fmt.Sprintf("%s/charge/status", wb.uri)
|
||||||
|
err := wb.GetJSON(uri, &res)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status implements the api.Charger interface
|
||||||
|
func (wb *ConnectIq) Status() (api.ChargeStatus, error) {
|
||||||
|
resp, err := wb.status()
|
||||||
|
|
||||||
|
res := api.StatusNone
|
||||||
|
switch resp.Status {
|
||||||
|
case "ready":
|
||||||
|
res = api.StatusA
|
||||||
|
case "ev":
|
||||||
|
res = api.StatusB
|
||||||
|
case "charging":
|
||||||
|
res = api.StatusC
|
||||||
|
default:
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("invalid status: %s", resp.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled implements the api.Charger interface
|
||||||
|
func (wb *ConnectIq) Enabled() (bool, error) {
|
||||||
|
var res connectiq.ChargeMaxAmps
|
||||||
|
uri := fmt.Sprintf("%s/charge/max_amps", wb.uri)
|
||||||
|
err := wb.GetJSON(uri, &res)
|
||||||
|
return res.Max > 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable implements the api.Charger interface
|
||||||
|
func (wb *ConnectIq) Enable(enable bool) error {
|
||||||
|
var curr int64
|
||||||
|
if enable {
|
||||||
|
curr = wb.curr
|
||||||
|
}
|
||||||
|
return wb.setCurrent(curr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wb *ConnectIq) setCurrent(current int64) error {
|
||||||
|
uri := fmt.Sprintf("%s/charge/max_amps", wb.uri)
|
||||||
|
|
||||||
|
data := struct {
|
||||||
|
Max int64 `json:"max"`
|
||||||
|
}{
|
||||||
|
Max: current,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
|
||||||
|
if err == nil {
|
||||||
|
_, err = wb.DoBody(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxCurrent implements the api.Charger interface
|
||||||
|
func (wb *ConnectIq) MaxCurrent(current int64) error {
|
||||||
|
err := wb.setCurrent(current)
|
||||||
|
if err == nil {
|
||||||
|
wb.curr = current
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ api.Meter = (*ConnectIq)(nil)
|
||||||
|
|
||||||
|
// CurrentPower implements the api.Meter interface
|
||||||
|
func (wb *ConnectIq) CurrentPower() (float64, error) {
|
||||||
|
res, err := wb.meterG()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return (res.Pow[0] + res.Pow[1] + res.Pow[2]) * 1e3, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ api.MeterEnergy = (*ConnectIq)(nil)
|
||||||
|
|
||||||
|
// TotalEnergy implements the api.MeterEnergy interface
|
||||||
|
func (wb *ConnectIq) TotalEnergy() (float64, error) {
|
||||||
|
var res connectiq.MeterRead
|
||||||
|
uri := fmt.Sprintf("%s/meter/read", wb.uri)
|
||||||
|
err := wb.GetJSON(uri, &res)
|
||||||
|
return res.Energy, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ api.MeterCurrent = (*ConnectIq)(nil)
|
||||||
|
|
||||||
|
// Currents implements the api.MeterCurrent interface
|
||||||
|
func (wb *ConnectIq) Currents() (float64, float64, float64, error) {
|
||||||
|
res, err := wb.meterG()
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
return res.Curr[0], res.Curr[1], res.Curr[2], nil
|
||||||
|
}
|
||||||
24
charger/connectiq/types.go
Normal file
24
charger/connectiq/types.go
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package connectiq
|
||||||
|
|
||||||
|
type ChargeStatus struct {
|
||||||
|
Amps int64 `json:"amps"`
|
||||||
|
Pp int64 `json:"pp"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Std int64 `json:"std"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChargeMaxAmps struct {
|
||||||
|
Max int64 `json:"max"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MeterStatus struct {
|
||||||
|
App []float64 `json:"app"`
|
||||||
|
Curr []float64 `json:"curr"`
|
||||||
|
Fac []float64 `json:"fac"`
|
||||||
|
Pow []float64 `json:"pow"`
|
||||||
|
Volt []float64 `json:"volt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MeterRead struct {
|
||||||
|
Energy float64 `json:"energy"`
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue