evcc-io/util/sponsor/victron.go
2026-04-29 12:49:44 +00:00

102 lines
2.6 KiB
Go

package sponsor
// LICENSE
// Copyright (c) evcc.io (andig, naltatis, premultiply)
// 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 (
"context"
"errors"
"os/exec"
"runtime"
"strings"
"time"
)
// checkVictron checks if the hardware is a supported victron device and returns sponsor subject
func checkVictron() string {
vd, err := victronDeviceInfo()
if err != nil {
return ""
}
return checkHardware("victron", map[string]string{
"board": vd.Board,
"productId": vd.ProductId,
"vrmId": vd.VrmId,
"serial": vd.Serial,
})
}
type victronDevice struct {
ProductId string
VrmId string
Serial string
Board string
}
func commandExists(cmd string) error {
_, err := exec.LookPath(cmd)
return err
}
func executeCommand(ctx context.Context, cmd string, args ...string) (string, error) {
command := exec.CommandContext(ctx, cmd, args...)
output, err := command.Output()
if err != nil {
return "", err
}
result := strings.TrimSpace(string(output))
if result == "" {
return "", errors.New("empty output")
}
return result, nil
}
func victronDeviceInfo() (victronDevice, error) {
if runtime.GOOS != "linux" {
return victronDevice{}, errors.New("non-linux os")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var vd victronDevice
commands := []struct {
field *string
cmd string
args []string
}{
{field: &vd.Board, cmd: "/usr/bin/board-compat"},
{field: &vd.ProductId, cmd: "/usr/bin/product-id"},
{field: &vd.VrmId, cmd: "/sbin/get-unique-id"},
{field: &vd.Serial, cmd: "/opt/victronenergy/venus-eeprom/eeprom", args: []string{"--show", "serial-number"}},
}
for _, detail := range commands {
if err := commandExists(detail.cmd); err != nil {
return vd, errors.New("cmd not found: " + detail.cmd)
}
output, err := executeCommand(ctx, detail.cmd, detail.args...)
if err != nil {
return vd, err
}
*detail.field = output
}
return vd, nil
}