Add javascript plugin (#510)
This commit is contained in:
parent
6724f04e04
commit
3455042e3f
6 changed files with 137 additions and 3 deletions
15
README.md
15
README.md
|
|
@ -242,7 +242,7 @@ hems:
|
|||
|
||||
to the configuration. The EVCC loadpoints can then be added to the SHM configuration. When SHM is used, the ratio of Grid to PV Power for the **Min+PV** mode can be adjusted in
|
||||
Sunny-Portal via the "Optional energy demand" slider. When the amount of configured PV is not available, charging suspends like in **PV** mode. So, pushing the slider completely
|
||||
to the left makes **Min+PV** behave as described above. Pushing completely to the right makes **Min+PV** mode behave like **PV** mode.
|
||||
to the left makes **Min+PV** behave as described above. Pushing completely to the right makes **Min+PV** mode behave like **PV** mode.
|
||||
|
||||
## Plugins
|
||||
|
||||
|
|
@ -265,9 +265,20 @@ add:
|
|||
|
||||
The `calc` plugin is useful e.g. to combine power values if import and export power are separate like with S0 meters. Use `scale` on one of the elements to implement a subtraction.
|
||||
|
||||
### Javascript (read only)
|
||||
|
||||
The `js` plugin is able to execute Javascript code from the `script` tag. Useful for quick prototyping:
|
||||
|
||||
```yaml
|
||||
type: js
|
||||
script: |
|
||||
var res = 500;
|
||||
2 * res; // returns 1000
|
||||
```
|
||||
|
||||
### Modbus (read only)
|
||||
|
||||
The `modbus` plugins is able to read data from any Modbus meter or SunSpec-compatible solar inverter. Many meters are already pre-configured (see [MBMD Supported Devices](https://github.com/volkszaehler/mbmd#supported-devices)).
|
||||
The `modbus` plugin is able to read data from any Modbus meter or SunSpec-compatible solar inverter. Many meters are already pre-configured (see [MBMD Supported Devices](https://github.com/volkszaehler/mbmd#supported-devices)).
|
||||
|
||||
The meter configuration consists of the actual physical connection and the value to be read.
|
||||
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -43,6 +43,7 @@ require (
|
|||
github.com/mxschmitt/golang-combinations v1.1.0
|
||||
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/spf13/jwalterweatherman v1.1.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
|
|
@ -53,6 +54,7 @@ require (
|
|||
github.com/volkszaehler/mbmd v0.0.0-20201205173745-5106cb0b334e
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73
|
||||
gopkg.in/ini.v1 v1.62.0
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||
)
|
||||
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -244,6 +244,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU=
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
|
|
@ -412,6 +414,8 @@ gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
|||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
|
||||
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ func NewFloatGetterFromConfig(config Config) (res func() (float64, error), err e
|
|||
if prov, err = NewHTTPProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.FloatGetter
|
||||
}
|
||||
case "js":
|
||||
var prov *Javascript
|
||||
if prov, err = NewJavascriptProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.FloatGetter
|
||||
}
|
||||
case "websocket", "ws":
|
||||
var prov *Socket
|
||||
if prov, err = NewSocketProviderFromConfig(config.Other); err == nil {
|
||||
|
|
@ -115,6 +120,11 @@ func NewIntGetterFromConfig(config Config) (res func() (int64, error), err error
|
|||
if prov, err = NewHTTPProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.IntGetter
|
||||
}
|
||||
case "js":
|
||||
var prov *Javascript
|
||||
if prov, err = NewJavascriptProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.IntGetter
|
||||
}
|
||||
case "websocket", "ws":
|
||||
var prov *Socket
|
||||
if prov, err = NewSocketProviderFromConfig(config.Other); err == nil {
|
||||
|
|
@ -159,6 +169,11 @@ func NewStringGetterFromConfig(config Config) (res func() (string, error), err e
|
|||
if prov, err = NewHTTPProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.StringGetter
|
||||
}
|
||||
case "js":
|
||||
var prov *Javascript
|
||||
if prov, err = NewJavascriptProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.StringGetter
|
||||
}
|
||||
case "websocket", "ws":
|
||||
var prov *Socket
|
||||
if prov, err = NewSocketProviderFromConfig(config.Other); err == nil {
|
||||
|
|
@ -200,6 +215,11 @@ func NewBoolGetterFromConfig(config Config) (res func() (bool, error), err error
|
|||
if prov, err = NewHTTPProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.BoolGetter
|
||||
}
|
||||
case "js":
|
||||
var prov *Javascript
|
||||
if prov, err = NewJavascriptProviderFromConfig(config.Other); err == nil {
|
||||
res = prov.BoolGetter
|
||||
}
|
||||
case "websocket", "ws":
|
||||
var prov *Socket
|
||||
if prov, err = NewSocketProviderFromConfig(config.Other); err == nil {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ func NewHTTPProviderFromConfig(other map[string]interface{}) (*HTTP, error) {
|
|||
Scale float64
|
||||
Insecure bool
|
||||
Auth Auth
|
||||
}{Headers: make(map[string]string)}
|
||||
}{
|
||||
Headers: make(map[string]string),
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
95
provider/javascript.go
Normal file
95
provider/javascript.go
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"github.com/andig/evcc/util"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
// Javascript implements Javascript request provider
|
||||
type Javascript struct {
|
||||
log *util.Logger
|
||||
vm *otto.Otto
|
||||
script string
|
||||
}
|
||||
|
||||
// NewJavascriptProviderFromConfig creates a HTTP provider
|
||||
func NewJavascriptProviderFromConfig(other map[string]interface{}) (*Javascript, error) {
|
||||
cc := struct {
|
||||
Script string
|
||||
}{}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log := util.NewLogger("js")
|
||||
|
||||
p := &Javascript{
|
||||
log: log,
|
||||
vm: otto.New(),
|
||||
script: cc.Script,
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// FloatGetter parses float from request
|
||||
func (p *Javascript) FloatGetter() (res float64, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToFloat()
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// IntGetter parses int64 from request
|
||||
func (p *Javascript) IntGetter() (res int64, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToInteger()
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// StringGetter sends string request
|
||||
func (p *Javascript) StringGetter() (res string, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToString()
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// BoolGetter parses bool from request
|
||||
func (p *Javascript) BoolGetter() (res bool, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToBoolean()
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// // IntSetter sends int request
|
||||
// func (p *Javascript) IntSetter(param int64) error {
|
||||
// body := util.FormatValue(p.body, param)
|
||||
// _, err := p.request(body)
|
||||
// return err
|
||||
// }
|
||||
|
||||
// // StringSetter sends string request
|
||||
// func (p *Javascript) StringSetter(param string) error {
|
||||
// body := util.FormatValue(p.body, param)
|
||||
// _, err := p.request(body)
|
||||
// return err
|
||||
// }
|
||||
|
||||
// // BoolSetter sends bool request
|
||||
// func (p *Javascript) BoolSetter(param bool) error {
|
||||
// body := util.FormatValue(p.body, param)
|
||||
// _, err := p.request(body)
|
||||
// return err
|
||||
// }
|
||||
Loading…
Add table
Add a link
Reference in a new issue