Support NRGKick bluetooth (#120)
This commit is contained in:
parent
a44f4242fa
commit
12ca72ec2c
9 changed files with 586 additions and 22 deletions
|
|
@ -7,7 +7,7 @@ EVCC is an extensible EV Charge Controller with PV integration implemented in [G
|
|||
## Features
|
||||
|
||||
- simple and clean user interface
|
||||
- multiple [chargers](#charger): Wallbe, Phoenix (includes ESL Walli), go-eCharger, NRGKick, SimpleEVSE, EVSEWifi, KEBA/BMW, openWB, Mobile Charger Connect, any other charger using scripting
|
||||
- multiple [chargers](#charger): Wallbe, Phoenix (includes ESL Walli), go-eCharger, NRGKick (Bluetooth and Connect), SimpleEVSE, EVSEWifi, KEBA/BMW, openWB, Mobile Charger Connect, any other charger using scripting
|
||||
- multiple [meters](#meter): ModBus (Eastron SDM, MPM3PM, SBC ALE3 and many more), SMA Home Manager and SMA Energy Meter, KOSTAL Smart Energy Meter (KSEM, EMxx), any Sunspec-compatible inverter or home battery devices (Fronius, SMA, SolarEdge, KOSTAL, STECA, E3DC), Tesla PowerWall
|
||||
- different [vehicles](#vehicle) to show battery status: Audi (eTron), BMW (i3), Tesla, Nissan (Leaf), any other vehicle using scripting
|
||||
- [plugins](#plugins) for integrating with hardware devices and home automation: Modbus (meters and grid inverters), MQTT and shell scripts
|
||||
|
|
@ -136,7 +136,8 @@ Charger is responsible for handling EV state and adjusting charge current. Avail
|
|||
- `phoenix-evcc`: chargers with Phoenix EV-CC-AC1-M controllers (ModBus connection)
|
||||
- `simpleevse`: chargers with SimpleEVSE controllers connected via ModBus (e.g. OpenWB)
|
||||
- `evsewifi`: chargers with SimpleEVSE controllers using [SimpleEVSE-Wifi](https://github.com/CurtRod/SimpleEVSE-WiFi)
|
||||
- `nrgkick`: NRGKick chargers with Connect module
|
||||
- `nrgkick-bt`: NRGKick chargers with Bluetooth connector (Linux only, not supported on Docker)
|
||||
- `nrgkick-connect`: NRGKick chargers with Connect module
|
||||
- `go-e`: go-eCharger chargers
|
||||
- `keba`: KEBA KeContact P20/P30 and BMW chargers (see [Preparation](#keba-preparation))
|
||||
- `mcc`: Mobile Charger Connect devices (Audi, Bentley, Porsche)
|
||||
|
|
|
|||
|
|
@ -22,8 +22,10 @@ func NewFromConfig(log *util.Logger, typ string, other map[string]interface{}) a
|
|||
c = NewPhoenixEMCPFromConfig(log, other)
|
||||
case "phoenix-evcc":
|
||||
c = NewPhoenixEVCCFromConfig(log, other)
|
||||
case "nrgkick", "nrg", "kick":
|
||||
c = NewNRGKickFromConfig(log, other)
|
||||
case "nrgkick-bluetooth", "nrgkick-bt", "nrgble":
|
||||
c = NewNRGKickBLEFromConfig(log, other)
|
||||
case "nrgkick-connect", "nrgconnect":
|
||||
c = NewNRGKickConnectFromConfig(log, other)
|
||||
case "go-e", "goe":
|
||||
c = NewGoEFromConfig(log, other)
|
||||
case "evsewifi":
|
||||
|
|
|
|||
14
charger/nrgble.go
Normal file
14
charger/nrgble.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// +build !linux
|
||||
|
||||
package charger
|
||||
|
||||
import (
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/util"
|
||||
)
|
||||
|
||||
// NewNRGKickBLEFromConfig creates a NRGKickBLE charger from generic config
|
||||
func NewNRGKickBLEFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
|
||||
log.FATAL.Fatal("config: NRGKick bluetooth is only supported on linux")
|
||||
return nil
|
||||
}
|
||||
91
charger/nrgble/nrg_linux.go
Normal file
91
charger/nrgble/nrg_linux.go
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package nrgble
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/muka/go-bluetooth/api"
|
||||
"github.com/muka/go-bluetooth/bluez/profile/adapter"
|
||||
"github.com/muka/go-bluetooth/bluez/profile/agent"
|
||||
"github.com/muka/go-bluetooth/bluez/profile/device"
|
||||
)
|
||||
|
||||
func FindDevice(a *adapter.Adapter1, hwaddr string) (*device.Device1, error) {
|
||||
dev, err := Discover(a, hwaddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dev == nil {
|
||||
return nil, errors.New("Device not found, is it advertising?")
|
||||
}
|
||||
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
func Discover(a *adapter.Adapter1, hwaddr string) (*device.Device1, error) {
|
||||
err := a.FlushDevices()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
discovery, cancel, err := api.Discover(a, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer cancel()
|
||||
|
||||
for ev := range discovery {
|
||||
dev, err1 := device.NewDevice1(ev.Path)
|
||||
if err != nil {
|
||||
return nil, err1
|
||||
}
|
||||
|
||||
if dev == nil || dev.Properties == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
p := dev.Properties
|
||||
|
||||
if p.Address != hwaddr {
|
||||
continue
|
||||
}
|
||||
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func Connect(dev *device.Device1, ag *agent.SimpleAgent, adapterID string) error {
|
||||
props, err := dev.GetProperties()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to load props: %s", err)
|
||||
}
|
||||
|
||||
if props.Connected {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !props.Paired || !props.Trusted {
|
||||
if err := dev.Pair(); err != nil {
|
||||
return fmt.Errorf("Pair failed: %s", err)
|
||||
}
|
||||
|
||||
if err := agent.SetTrusted(adapterID, dev.Path()); err != nil {
|
||||
return fmt.Errorf("Set trusted failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !props.Connected {
|
||||
err = dev.Connect()
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "Connection refused") {
|
||||
return fmt.Errorf("Connect failed: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
65
charger/nrgble/service.go
Normal file
65
charger/nrgble/service.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package nrgble
|
||||
|
||||
const (
|
||||
InfoService = "8f75bba0-c903-11e4-9fe8-0002a5d6b15d"
|
||||
EnergyService = "0379e580-ad1b-11e4-8bdd-0002a5d6b15d"
|
||||
PowerService = "fd005380-b065-11e4-9ce2-0002a5d6b15d"
|
||||
VoltageCurrentService = "171bad00-b066-11e4-aeda-0002a5d6b15d"
|
||||
SettingsService = "14b3afc0-ad1b-11e4-baab-0002a5d6b15d"
|
||||
)
|
||||
|
||||
type Info struct {
|
||||
Current int `struc:"int8"` // appInfo[0]
|
||||
KWhPer100 int `struc:"int16"` // appInfo[1] / 10
|
||||
AmountPerKWh int `struc:"int8"` // appInfo[2] / 100
|
||||
FIEnabled int `struc:"int8"` // 1 == appInfo[3]
|
||||
ErrorCode int `struc:"int8"` // appInfo[4]
|
||||
Efficiency int `struc:"int8"` // appInfo[5]
|
||||
ChargingActive bool `struc:"int8"` // 1 == appInfo[6]
|
||||
PauseCharging bool `struc:"int8"` // 1 == appInfo[7]
|
||||
ChargingCurrentMax int `struc:"int8"` // appInfo[8]
|
||||
BLETransmissionPower int `struc:"int8"` // appInfo[9]
|
||||
}
|
||||
|
||||
type Energy struct {
|
||||
TotalEnergy int `struc:"uint32"` // energie02[0] / 1000
|
||||
EnergyLastCharge int `struc:"uint32"` // energie02[1] / 1000
|
||||
Energy2ndLastCharge int `struc:"uint32"` // energie02[2] / 1000
|
||||
Energy3rdLastCharge int `struc:"uint32"` // energie02[3] / 1000
|
||||
ChargingEnergyLimit int `struc:"uint16"` // energie02[4] / 100
|
||||
}
|
||||
|
||||
type Power struct {
|
||||
TotalPower int `struc:"uint16"` // leistung[0] / 100
|
||||
L1 int `struc:"uint16"` // leistung[1] / 100
|
||||
L2 int `struc:"uint16"` // leistung[2] / 100
|
||||
L3 int `struc:"uint16"` // leistung[3] / 100
|
||||
PeakPower int `struc:"uint16"` // leistung[4] / 100;
|
||||
Frequency int `struc:"uint16"` // leistung[5] / 100
|
||||
Temperature int `struc:"int16"` // leistung[6]
|
||||
RemainingDistance int `struc:"uint16"` // leistung[7] / 10
|
||||
Costs int `struc:"uint16"` // leistung[8] / 100
|
||||
CPSignal int `struc:"int8"` // round(((leistung[9] << 8) / 100) + 0.4, 1)
|
||||
}
|
||||
|
||||
type VoltageCurrent struct {
|
||||
VoltageL1 int `struc:"uint16"` // voltageAndCurrent[0] / 10
|
||||
VoltageL2 int `struc:"uint16"` // voltageAndCurrent[1] / 10
|
||||
VoltageL3 int `struc:"uint16"` // voltageAndCurrent[2] / 10
|
||||
CurrentL1 int `struc:"uint16"` // voltageAndCurrent[3] / 100
|
||||
CurrentL2 int `struc:"uint16"` // voltageAndCurrent[4] / 100
|
||||
CurrentL3 int `struc:"uint16"` // voltageAndCurrent[5] / 100
|
||||
}
|
||||
|
||||
type Settings struct {
|
||||
PIN int `struc:"uint16"` // H SettingsPIN
|
||||
Current int `struc:"uint8"` // B SettingsChargingCurrentValue
|
||||
ChargingEnergyLimit int `struc:"uint16"` // H SettingsChargingEnergyOff
|
||||
KWhPer100 int `struc:"uint16"` // H round(SettingsKWhPer100Value * 10)
|
||||
AmountPerKWh int `struc:"uint8"` // B round(SettingsAmountPerKWhValue * 100)
|
||||
Pad int `struc:"[2]pad"` // xx
|
||||
Efficiency int `struc:"uint8"` // B SettingsEfficacyValue
|
||||
PauseCharging bool `struc:"uint8"` // B 1 if SettingsPauseCharging else 0
|
||||
BLETransmissionPower int `struc:"int8"` // b SettingsBLETransmissionPowerValue
|
||||
PadTail int `struc:"[5]pad"` // xxxxx
|
||||
}
|
||||
365
charger/nrgble_linux.go
Normal file
365
charger/nrgble_linux.go
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
package charger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/charger/nrgble"
|
||||
"github.com/andig/evcc/util"
|
||||
"github.com/godbus/dbus"
|
||||
"github.com/lunixbochs/struc"
|
||||
"github.com/muka/go-bluetooth/bluez/profile/adapter"
|
||||
"github.com/muka/go-bluetooth/bluez/profile/agent"
|
||||
"github.com/muka/go-bluetooth/bluez/profile/device"
|
||||
"github.com/muka/go-bluetooth/hw"
|
||||
)
|
||||
|
||||
// NRGKickBLE charger implementation
|
||||
type NRGKickBLE struct {
|
||||
log *util.Logger
|
||||
timer *time.Timer
|
||||
adapter *adapter.Adapter1
|
||||
agent *agent.SimpleAgent
|
||||
dev *device.Device1
|
||||
device string
|
||||
macaddress string
|
||||
pin int
|
||||
}
|
||||
|
||||
// NewNRGKickBLEFromConfig creates a NRGKickBLE charger from generic config
|
||||
func NewNRGKickBLEFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
|
||||
cc := struct{ Device, MacAddress, PIN string }{
|
||||
Device: "hci0",
|
||||
}
|
||||
util.DecodeOther(log, other, &cc)
|
||||
|
||||
// decode PIN with leading zero
|
||||
pin, err := strconv.Atoi(cc.PIN)
|
||||
if err != nil {
|
||||
log.FATAL.Fatalf("config: invalid pin '%s'", cc.PIN)
|
||||
}
|
||||
|
||||
return NewNRGKickBLE(cc.Device, cc.MacAddress, pin)
|
||||
}
|
||||
|
||||
// NewNRGKickBLE creates NRGKickBLE charger
|
||||
func NewNRGKickBLE(device, macaddress string, pin int) *NRGKickBLE {
|
||||
logger := util.NewLogger("nrgbt")
|
||||
logger.WARN.Println("-- experimental --")
|
||||
|
||||
// set LE mode
|
||||
btmgmt := hw.NewBtMgmt(device)
|
||||
|
||||
if len(os.Getenv("DOCKER")) > 0 {
|
||||
btmgmt.BinPath = "./bin/docker-btmgmt"
|
||||
}
|
||||
|
||||
err := btmgmt.SetPowered(false)
|
||||
if err == nil {
|
||||
err = btmgmt.SetLe(true)
|
||||
if err == nil {
|
||||
err = btmgmt.SetBredr(false)
|
||||
if err == nil {
|
||||
err = btmgmt.SetPowered(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.FATAL.Fatal(err)
|
||||
}
|
||||
|
||||
adapt, err := adapter.NewAdapter1FromAdapterID(device)
|
||||
if err != nil {
|
||||
logger.FATAL.Fatal(err)
|
||||
}
|
||||
|
||||
//Connect DBus System bus
|
||||
conn, err := dbus.SystemBus()
|
||||
if err != nil {
|
||||
logger.FATAL.Fatal(err)
|
||||
}
|
||||
|
||||
// do not reuse agent0 from service
|
||||
agent.NextAgentPath()
|
||||
|
||||
ag := agent.NewSimpleAgent()
|
||||
err = agent.ExposeAgent(conn, ag, agent.CapNoInputNoOutput, true)
|
||||
if err != nil {
|
||||
logger.FATAL.Fatal(err)
|
||||
}
|
||||
|
||||
nrg := &NRGKickBLE{
|
||||
log: logger,
|
||||
timer: time.NewTimer(1),
|
||||
device: device,
|
||||
macaddress: macaddress,
|
||||
pin: pin,
|
||||
adapter: adapt,
|
||||
agent: ag,
|
||||
}
|
||||
|
||||
return nrg
|
||||
}
|
||||
|
||||
func (nrg *NRGKickBLE) connect() (*device.Device1, error) {
|
||||
dev, err := nrgble.FindDevice(nrg.adapter, nrg.macaddress)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("findDevice: %s", err)
|
||||
}
|
||||
|
||||
err = nrgble.Connect(dev, nrg.agent, nrg.device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
func (nrg *NRGKickBLE) close() {
|
||||
if nrg.dev != nil {
|
||||
nrg.dev.Close()
|
||||
nrg.dev = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (nrg *NRGKickBLE) waitTimer() {
|
||||
<-nrg.timer.C
|
||||
}
|
||||
|
||||
func (nrg *NRGKickBLE) setTimer() {
|
||||
nrg.timer.Stop() // can be stopped without reading as channel is always drained
|
||||
nrg.timer.Reset(2 * time.Second)
|
||||
}
|
||||
|
||||
func (nrg *NRGKickBLE) read(service string) ([]byte, error) {
|
||||
nrg.waitTimer()
|
||||
defer nrg.setTimer()
|
||||
|
||||
if nrg.dev == nil {
|
||||
dev, err := nrg.connect()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
nrg.dev = dev
|
||||
}
|
||||
|
||||
char, err := nrg.dev.GetCharByUUID(service)
|
||||
if err != nil {
|
||||
nrg.close()
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
b, err := char.ReadValue(map[string]interface{}{})
|
||||
if err != nil {
|
||||
nrg.close()
|
||||
return []byte{}, err
|
||||
}
|
||||
nrg.log.TRACE.Printf("read %s %0x", service, b)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (nrg *NRGKickBLE) write(service string, b []byte) error {
|
||||
nrg.waitTimer()
|
||||
defer nrg.setTimer()
|
||||
|
||||
if nrg.dev == nil {
|
||||
dev, err := nrg.connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nrg.dev = dev
|
||||
}
|
||||
|
||||
nrg.log.TRACE.Printf("write %s %0x", service, b)
|
||||
char, err := nrg.dev.GetCharByUUID(service)
|
||||
if err != nil {
|
||||
nrg.close()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := char.WriteValue(b, map[string]interface{}{}); err != nil {
|
||||
nrg.close()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nrg *NRGKickBLE) defaultSettings(info nrgble.Info) nrgble.Settings {
|
||||
return nrgble.Settings{
|
||||
PIN: nrg.pin,
|
||||
ChargingEnergyLimit: 19997, // magic const for "disable"
|
||||
KWhPer100: info.KWhPer100,
|
||||
AmountPerKWh: info.AmountPerKWh,
|
||||
Efficiency: info.Efficiency,
|
||||
PauseCharging: info.PauseCharging,
|
||||
BLETransmissionPower: info.BLETransmissionPower,
|
||||
}
|
||||
}
|
||||
|
||||
// Status implements the Charger.Status interface
|
||||
func (nrg *NRGKickBLE) Status() (api.ChargeStatus, error) {
|
||||
b, err := nrg.read(nrgble.PowerService)
|
||||
if err != nil {
|
||||
return api.StatusF, err
|
||||
}
|
||||
|
||||
res := nrgble.Power{}
|
||||
if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
return api.StatusF, err
|
||||
}
|
||||
nrg.log.TRACE.Printf("power: %+v", res)
|
||||
|
||||
CPSignal := float64(res.CPSignal<<8)/100 + 0.4
|
||||
|
||||
if CPSignal >= 1.3 && CPSignal <= 7.5 {
|
||||
return api.StatusC, nil
|
||||
}
|
||||
|
||||
if CPSignal >= 1.3 && CPSignal <= 10.5 {
|
||||
return api.StatusB, nil
|
||||
}
|
||||
|
||||
return api.StatusA, nil
|
||||
}
|
||||
|
||||
// Enabled implements the Charger.Enabled interface
|
||||
func (nrg *NRGKickBLE) Enabled() (bool, error) {
|
||||
b, err := nrg.read(nrgble.InfoService)
|
||||
if err != nil {
|
||||
nrg.log.TRACE.Println(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
res := nrgble.Info{}
|
||||
if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
return false, err
|
||||
}
|
||||
nrg.log.TRACE.Printf("info: %+v", res)
|
||||
|
||||
return !res.PauseCharging, nil
|
||||
}
|
||||
|
||||
// Enable implements the Charger.Enable interface
|
||||
func (nrg *NRGKickBLE) Enable(enable bool) error {
|
||||
b, err := nrg.read(nrgble.InfoService)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := nrgble.Info{}
|
||||
if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
return err
|
||||
}
|
||||
nrg.log.TRACE.Printf("info: %+v", res)
|
||||
|
||||
settings := nrg.defaultSettings(res)
|
||||
settings.PauseCharging = !enable
|
||||
|
||||
var out bytes.Buffer
|
||||
if err := struc.Pack(&out, &settings); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nrg.write(nrgble.SettingsService, out.Bytes())
|
||||
}
|
||||
|
||||
// MaxCurrent implements the Charger.MaxCurrent interface
|
||||
func (nrg *NRGKickBLE) MaxCurrent(current int64) error {
|
||||
b, err := nrg.read(nrgble.InfoService)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := nrgble.Info{}
|
||||
if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
return err
|
||||
}
|
||||
nrg.log.TRACE.Printf("info: %+v", res)
|
||||
|
||||
settings := nrg.defaultSettings(res)
|
||||
settings.Current = int(current)
|
||||
|
||||
var out bytes.Buffer
|
||||
if err := struc.Pack(&out, &settings); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nrg.write(nrgble.SettingsService, out.Bytes())
|
||||
}
|
||||
|
||||
// CurrentPower implements the Meter interface.
|
||||
func (nrg *NRGKickBLE) CurrentPower() (float64, error) {
|
||||
b, err := nrg.read(nrgble.PowerService)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
res := nrgble.Power{}
|
||||
if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
nrg.log.TRACE.Printf("power: %+v", res)
|
||||
|
||||
return float64(res.TotalPower) * 10, nil
|
||||
}
|
||||
|
||||
// TotalEnergy implements the MeterEnergy interface.
|
||||
func (nrg *NRGKickBLE) TotalEnergy() (float64, error) {
|
||||
b, err := nrg.read(nrgble.EnergyService)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
res := nrgble.Energy{}
|
||||
if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
nrg.log.TRACE.Printf("energy: %+v", res)
|
||||
|
||||
return float64(res.TotalEnergy) / 1000, nil
|
||||
}
|
||||
|
||||
// Currents implements the MeterCurrent interface.
|
||||
func (nrg *NRGKickBLE) Currents() (float64, float64, float64, error) {
|
||||
b, err := nrg.read(nrgble.VoltageCurrentService)
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
res := nrgble.VoltageCurrent{}
|
||||
if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
nrg.log.TRACE.Printf("voltage/current: %+v", res)
|
||||
|
||||
return float64(res.CurrentL1) / 100,
|
||||
float64(res.CurrentL2) / 100,
|
||||
float64(res.CurrentL3) / 100,
|
||||
nil
|
||||
}
|
||||
|
||||
// ChargedEnergy implements the ChargeRater interface.
|
||||
// NOTE: apparently shows energy of a stopped charging session, hence substituted by TotalEnergy
|
||||
// func (nrg *NRGKickBLE) ChargedEnergy() (float64, error) {
|
||||
// nrg.log.TRACE.Print("read EnergyService")
|
||||
// b, err := nrg.read(nrgble.EnergyService)
|
||||
// if err != nil {
|
||||
// return 0, err
|
||||
// }
|
||||
|
||||
// res := nrgble.Energy{}
|
||||
// if err := struc.Unpack(bytes.NewReader(b), &res); err != nil {
|
||||
// return 0, err
|
||||
// }
|
||||
|
||||
// nrg.log.TRACE.Printf("energy: %+v", res)
|
||||
|
||||
// return float64(res.EnergyLastCharge) / 1000, nil
|
||||
// }
|
||||
|
|
@ -57,26 +57,26 @@ type NRGDeviceMetadata struct {
|
|||
Password string
|
||||
}
|
||||
|
||||
// NRGKick charger implementation
|
||||
type NRGKick struct {
|
||||
// NRGKickConnect charger implementation
|
||||
type NRGKickConnect struct {
|
||||
*util.HTTPHelper
|
||||
IP string
|
||||
MacAddress string
|
||||
Password string
|
||||
}
|
||||
|
||||
// NewNRGKickFromConfig creates a NRGKick charger from generic config
|
||||
func NewNRGKickFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
|
||||
// NewNRGKickConnectFromConfig creates a NRGKickConnect charger from generic config
|
||||
func NewNRGKickConnectFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
|
||||
cc := struct{ IP, MacAddress, Password string }{}
|
||||
util.DecodeOther(log, other, &cc)
|
||||
|
||||
return NewNRGKick(cc.IP, cc.MacAddress, cc.Password)
|
||||
return NewNRGKickConnect(cc.IP, cc.MacAddress, cc.Password)
|
||||
}
|
||||
|
||||
// NewNRGKick creates NRGKick charger
|
||||
func NewNRGKick(IP, MacAddress, Password string) *NRGKick {
|
||||
nrg := &NRGKick{
|
||||
HTTPHelper: util.NewHTTPHelper(util.NewLogger("kick")),
|
||||
// NewNRGKickConnect creates NRGKickConnect charger
|
||||
func NewNRGKickConnect(IP, MacAddress, Password string) *NRGKickConnect {
|
||||
nrg := &NRGKickConnect{
|
||||
HTTPHelper: util.NewHTTPHelper(util.NewLogger("nrgc")),
|
||||
IP: IP,
|
||||
MacAddress: MacAddress,
|
||||
Password: Password,
|
||||
|
|
@ -87,11 +87,11 @@ func NewNRGKick(IP, MacAddress, Password string) *NRGKick {
|
|||
return nrg
|
||||
}
|
||||
|
||||
func (nrg *NRGKick) apiURL(api apiFunction) string {
|
||||
func (nrg *NRGKickConnect) apiURL(api apiFunction) string {
|
||||
return fmt.Sprintf("%s/api/%s/%s", nrg.IP, api, nrg.MacAddress)
|
||||
}
|
||||
|
||||
func (nrg *NRGKick) getJSON(url string, result interface{}) error {
|
||||
func (nrg *NRGKickConnect) getJSON(url string, result interface{}) error {
|
||||
b, err := nrg.GetJSON(url, result)
|
||||
if err != nil && len(b) > 0 {
|
||||
var error NRGResponse
|
||||
|
|
@ -105,7 +105,7 @@ func (nrg *NRGKick) getJSON(url string, result interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (nrg *NRGKick) putJSON(url string, request interface{}) error {
|
||||
func (nrg *NRGKickConnect) putJSON(url string, request interface{}) error {
|
||||
b, err := nrg.PutJSON(url, request)
|
||||
if err != nil && len(b) == 0 {
|
||||
return err
|
||||
|
|
@ -120,12 +120,12 @@ func (nrg *NRGKick) putJSON(url string, request interface{}) error {
|
|||
}
|
||||
|
||||
// Status implements the Charger.Status interface
|
||||
func (nrg *NRGKick) Status() (api.ChargeStatus, error) {
|
||||
func (nrg *NRGKickConnect) Status() (api.ChargeStatus, error) {
|
||||
return api.StatusC, nil
|
||||
}
|
||||
|
||||
// Enabled implements the Charger.Enabled interface
|
||||
func (nrg *NRGKick) Enabled() (bool, error) {
|
||||
func (nrg *NRGKickConnect) Enabled() (bool, error) {
|
||||
var settings NRGSettings
|
||||
err := nrg.getJSON(nrg.apiURL(apiSettings), settings)
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ func (nrg *NRGKick) Enabled() (bool, error) {
|
|||
}
|
||||
|
||||
// Enable implements the Charger.Enable interface
|
||||
func (nrg *NRGKick) Enable(enable bool) error {
|
||||
func (nrg *NRGKickConnect) Enable(enable bool) error {
|
||||
settings := NRGSettings{}
|
||||
settings.Values.DeviceMetadata.Password = nrg.Password
|
||||
settings.Values.ChargingStatus.Charging = &enable
|
||||
|
|
@ -142,7 +142,7 @@ func (nrg *NRGKick) Enable(enable bool) error {
|
|||
}
|
||||
|
||||
// MaxCurrent implements the Charger.MaxCurrent interface
|
||||
func (nrg *NRGKick) MaxCurrent(current int64) error {
|
||||
func (nrg *NRGKickConnect) MaxCurrent(current int64) error {
|
||||
settings := NRGSettings{}
|
||||
settings.Values.DeviceMetadata.Password = nrg.Password
|
||||
settings.Values.ChargingCurrent.Value = float64(current)
|
||||
|
|
@ -151,7 +151,7 @@ func (nrg *NRGKick) MaxCurrent(current int64) error {
|
|||
}
|
||||
|
||||
// CurrentPower implements the Meter interface.
|
||||
func (nrg *NRGKick) CurrentPower() (float64, error) {
|
||||
func (nrg *NRGKickConnect) CurrentPower() (float64, error) {
|
||||
var measurements NRGMeasurements
|
||||
err := nrg.getJSON(nrg.apiURL(apiMeasurements), measurements)
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ func (nrg *NRGKick) CurrentPower() (float64, error) {
|
|||
}
|
||||
|
||||
// ChargedEnergy implements the ChargeRater interface.
|
||||
func (nrg *NRGKick) ChargedEnergy() (float64, error) {
|
||||
func (nrg *NRGKickConnect) ChargedEnergy() (float64, error) {
|
||||
var measurements NRGMeasurements
|
||||
err := nrg.getJSON(nrg.apiURL(apiMeasurements), measurements)
|
||||
|
||||
5
go.mod
5
go.mod
|
|
@ -9,6 +9,7 @@ require (
|
|||
github.com/benbjohnson/clock v1.0.0
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||
github.com/godbus/dbus v4.1.0+incompatible
|
||||
github.com/golang/mock v1.4.3
|
||||
github.com/gorilla/handlers v1.4.2
|
||||
github.com/gorilla/mux v1.7.4
|
||||
|
|
@ -21,10 +22,14 @@ require (
|
|||
github.com/joeshaw/carwings v0.0.0-20191118152321-61b46581307a
|
||||
github.com/jsgoecke/tesla v0.0.0-20190206234002-112508e1374e
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/lunixbochs/struc v0.0.0-20190916212049-a5c72983bc42
|
||||
github.com/mitchellh/mapstructure v1.3.0
|
||||
github.com/mjibson/esc v0.2.0
|
||||
github.com/muka/go-bluetooth v0.0.0-20200505070311-0c1993e4ff21
|
||||
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/common v0.4.0
|
||||
github.com/smartystreets/assertions v1.0.0 // indirect
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/jwalterweatherman v1.1.0
|
||||
github.com/spf13/viper v1.6.3
|
||||
|
|
|
|||
21
go.sum
21
go.sum
|
|
@ -10,8 +10,10 @@ github.com/alecthomas/participle v0.4.4 h1:ZhPi9STNpixhITQx0RuoA/3UqCMu3cLsJVCfp
|
|||
github.com/alecthomas/participle v0.4.4/go.mod h1:HfdmEuwvr12HXQN44HPWXR0lHmVolVYe4dyL6lQ3duY=
|
||||
github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alvaroloes/enumer v1.1.2 h1:5khqHB33TZy1GWCO/lZwcroBFh7u+0j40T83VUbfAMY=
|
||||
github.com/alvaroloes/enumer v1.1.2/go.mod h1:FxrjvuXoDAx9isTJrv4c+T410zFi0DtXIT0m65DJ+Wo=
|
||||
|
|
@ -47,6 +49,8 @@ github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJ
|
|||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
|
||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
|
|
@ -61,6 +65,8 @@ github.com/goburrow/modbus v0.1.0 h1:DejRZY73nEM6+bt5JSP6IsFolJ9dVcqxsYbpLbeW/ro
|
|||
github.com/goburrow/modbus v0.1.0/go.mod h1:Kx552D5rLIS8E7TyUwQ/UdHEqvX5T8tyiGBTlzMcZBg=
|
||||
github.com/goburrow/serial v0.1.0 h1:v2T1SQa/dlUqQiYIT8+Cu7YolfqAi3K96UmhwYyuSrA=
|
||||
github.com/goburrow/serial v0.1.0/go.mod h1:sAiqG0nRVswsm1C97xsttiYCzSLBmUZ/VSlVLZJ8haA=
|
||||
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
|
||||
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
|
|
@ -71,6 +77,7 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
|
|
@ -127,6 +134,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C
|
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
|
|
@ -137,6 +146,8 @@ github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2t
|
|||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
|
||||
github.com/lestrrat-go/strftime v1.0.1 h1:o7qz5pmLzPDLyGW4lG6JvTKPUfTFXwe+vOamIYWtnVU=
|
||||
github.com/lestrrat-go/strftime v1.0.1/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g=
|
||||
github.com/lunixbochs/struc v0.0.0-20190916212049-a5c72983bc42 h1:PzBD7QuxXSgSu61TKXxRwVGzWO5d9QZ0HxFFpndZMCg=
|
||||
github.com/lunixbochs/struc v0.0.0-20190916212049-a5c72983bc42/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
|
|
@ -157,6 +168,8 @@ github.com/mjibson/esc v0.2.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1
|
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/muka/go-bluetooth v0.0.0-20200505070311-0c1993e4ff21 h1:ivI663FFGVCmxfn2r/f+fDpYDE9/+IhO5f19OL0zgxg=
|
||||
github.com/muka/go-bluetooth v0.0.0-20200505070311-0c1993e4ff21/go.mod h1:9Y4iuJfFe4N3afRt1qKpHU7vKUqyaWm/wJk2QEk6hgM=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da h1:qiPWuGGr+1GQE6s9NPSK8iggR/6x/V+0snIoOPYsBgc=
|
||||
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8=
|
||||
|
|
@ -180,6 +193,7 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
|
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
|
|
@ -190,8 +204,12 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
|
||||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
|
@ -222,6 +240,7 @@ github.com/stretchr/testify v1.5.0 h1:DMOzIV76tmoDNE9pX6RSN0aDtCYeCg5VueieJaAo1u
|
|||
github.com/stretchr/testify v1.5.0/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/suapapa/go_eddystone v0.0.0-20190827074641-8d8c1bb79363/go.mod h1:O/oFfbntg0b1z5NM/IGoTMKYPO3lkzPSA53E+J99lDU=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e h1:IWllFTiDjjLIf2oeKxpIUmtiDV5sn71VgeQgg6vcE7k=
|
||||
|
|
@ -274,6 +293,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -308,6 +328,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue