Merge pull request #131475 from mweinelt/evcc

This commit is contained in:
Martin Weinelt 2022-11-22 01:13:25 +01:00 committed by GitHub
commit 69335c46c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 328 additions and 0 deletions

View file

@ -278,6 +278,16 @@
<link linkend="opt-services.prometheus.sachet.enable">services.prometheus.sachet</link>.
</para>
</listitem>
<listitem>
<para>
<link xlink:href="https://evcc.io">EVCC</link> is an EV charge
controller with PV integration. It supports a multitude of
chargers, meters, vehicle APIs and more and ties that together
with a well-tested backend and a lightweight web frontend.
Available as
<link linkend="opt-services.evcc.enable">services.evcc</link>.
</para>
</listitem>
<listitem>
<para>
<link xlink:href="https://github.com/leetronics/infnoise">infnoise</link>,

View file

@ -98,6 +98,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [Sachet](https://github.com/messagebird/sachet/), an SMS alerting tool for the Prometheus Alertmanager. Available as [services.prometheus.sachet](#opt-services.prometheus.sachet.enable).
- [EVCC](https://evcc.io) is an EV charge controller with PV integration. It supports a multitude of chargers, meters, vehicle APIs and more and ties that together with a well-tested backend and a lightweight web frontend. Available as [services.evcc](#opt-services.evcc.enable).
- [infnoise](https://github.com/leetronics/infnoise), a hardware True Random Number Generator dongle.
Available as [services.infnoise](options.html#opt-services.infnoise.enable).

View file

@ -491,6 +491,7 @@
./services/hardware/vdr.nix
./services/home-automation/home-assistant.nix
./services/home-automation/zigbee2mqtt.nix
./services/home-automation/evcc.nix
./services/logging/SystemdJournal2Gelf.nix
./services/logging/awstats.nix
./services/logging/filebeat.nix

View file

@ -0,0 +1,92 @@
{ lib
, pkgs
, config
, ...
}:
with lib;
let
cfg = config.services.evcc;
format = pkgs.formats.yaml {};
configFile = format.generate "evcc.yml" cfg.settings;
package = pkgs.evcc;
in
{
meta.maintainers = with lib.maintainers; [ hexa ];
options.services.evcc = with types; {
enable = mkEnableOption (lib.mdDoc "EVCC, the extensible EV Charge Controller with PV integration");
extraArgs = mkOption {
type = listOf str;
default = [];
description = lib.mdDoc ''
Extra arguments to pass to the evcc executable.
'';
};
settings = mkOption {
type = format.type;
description = lib.mdDoc ''
evcc configuration as a Nix attribute set.
Check for possible options in the sample [evcc.dist.yaml](https://github.com/andig/evcc/blob/${package.version}/evcc.dist.yaml].
'';
};
};
config = mkIf cfg.enable {
systemd.services.evcc = {
after = [
"network-online.target"
"mosquitto.target"
];
wantedBy = [
"multi-user.target"
];
serviceConfig = {
ExecStart = "${package}/bin/evcc --config ${configFile} ${escapeShellArgs cfg.extraArgs}";
CapabilityBoundingSet = [ "" ];
DeviceAllow = [
"char-ttyUSB"
];
DevicePolicy = "closed";
DynamicUser = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups= true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
];
UMask = "0077";
User = "evcc";
};
};
};
meta.buildDocsInSandbox = false;
}

View file

@ -198,6 +198,7 @@ in {
etebase-server = handleTest ./etebase-server.nix {};
etesync-dav = handleTest ./etesync-dav.nix {};
extra-python-packages = handleTest ./extra-python-packages.nix {};
evcc = handleTest ./evcc.nix {};
fancontrol = handleTest ./fancontrol.nix {};
fcitx = handleTest ./fcitx {};
fenics = handleTest ./fenics.nix {};

96
nixos/tests/evcc.nix Normal file
View file

@ -0,0 +1,96 @@
import ./make-test-python.nix ({ pkgs, lib, ...} :
{
name = "evcc";
meta.maintainers = with lib.maintainers; [ hexa ];
nodes = {
machine = { config, ... }: {
services.evcc = {
enable = true;
settings = {
network = {
schema = "http";
host = "localhost";
port = 7070;
};
log = "info";
site = {
title = "NixOS Test";
meters = {
grid = "grid";
pv = "pv";
};
};
meters = [ {
type = "custom";
name = "grid";
power = {
source = "script";
cmd = "/bin/sh -c 'echo -4500'";
};
} {
type = "custom";
name = "pv";
power = {
source = "script";
cmd = "/bin/sh -c 'echo 7500'";
};
} ];
chargers = [ {
name = "dummy-charger";
type = "custom";
status = {
source = "script";
cmd = "/bin/sh -c 'echo charger status F'";
};
enabled = {
source = "script";
cmd = "/bin/sh -c 'echo charger enabled state false'";
};
enable = {
source = "script";
cmd = "/bin/sh -c 'echo set charger enabled state true'";
};
maxcurrent = {
source = "script";
cmd = "/bin/sh -c 'echo set charger max current 7200'";
};
} ];
loadpoints = [ {
title = "Dummy";
charger = "dummy-charger";
} ];
};
};
};
};
testScript = ''
start_all()
machine.wait_for_unit("evcc.service")
machine.wait_for_open_port(7070)
with subtest("Check package version propagates into frontend"):
machine.fail(
"curl --fail http://localhost:7070 | grep '0.0.1-alpha'"
)
machine.succeed(
"curl --fail http://localhost:7070 | grep '${pkgs.evcc.version}'"
)
with subtest("Check journal for errors"):
_, output = machine.execute("journalctl -o cat -u evcc.service")
assert "ERROR" not in output
with subtest("Check systemd hardening"):
_, output = machine.execute("systemd-analyze security evcc.service | grep -v ''")
machine.log(output)
'';
})

View file

@ -0,0 +1,96 @@
{ lib
, buildGoModule
, fetchFromGitHub
, fetchNpmDeps
, cacert
, go
, git
, enumer
, mockgen
, nodejs
, npmHooks
, nix-update-script
, nixosTests
, stdenv
}:
buildGoModule rec {
pname = "evcc";
version = "0.107.1";
src = fetchFromGitHub {
owner = "evcc-io";
repo = pname;
rev = version;
hash = "sha256-Yu7ebZ6WkLpdvmg7H9A1Sveyu9SRuQ+78gFrCZrYhCU=";
};
vendorHash = "sha256-10W1BNHcdP77m7lJ/mc+jQeUigoUid3K0wI4bUm5y+s=";
npmDeps = fetchNpmDeps {
inherit src;
hash = "sha256-+l5LuxJAjrTvOL5XEQ4OIktdupSpn6IqrNX5x4MRmNw=";
};
nativeBuildInputs = [
nodejs
npmHooks.npmConfigHook
];
overrideModAttrs = _: {
nativeBuildInputs = [
enumer
go
git
cacert
mockgen
];
preBuild = ''
make assets
'';
};
tags = [
"release"
];
ldflags = [
"-X github.com/evcc-io/evcc/server.Version=${version}"
"-X github.com/evcc-io/evcc/server.Commit=${src.rev}"
"-s"
"-w"
];
npmInstallFlags = [
"--legacy-peer-deps"
];
preBuild = ''
make ui
'';
doCheck = !stdenv.isDarwin; # tries to bind to local network, doesn't work in darwin sandbox
preCheck = ''
# requires network access
rm meter/template_test.go
'';
passthru = {
tests = {
inherit (nixosTests) evcc;
};
updateScript = nix-update-script {
attrPath = pname;
};
};
meta = with lib; {
description = "EV Charge Controller";
homepage = "https://evcc.io";
changelog = "https://github.com/andig/evcc/releases/tag/${version}";
license = licenses.mit;
maintainers = with maintainers; [ hexa ];
};
}

View file

@ -0,0 +1,26 @@
{ lib
, stdenv
, fetchFromGitHub
, buildGoModule
}:
buildGoModule rec {
pname = "enumer";
version = "1.5.7";
src = fetchFromGitHub {
owner = "dmarkham";
repo = "enumer";
rev = "refs/tags/v${version}";
hash = "sha256-2fVWrrWOiCtg7I3Lul2PgQ2u/qDEDioPSB61Tp0rfEo=";
};
vendorSha256 = "sha256-BmFv0ytRnjaB7z7Gb+38Fw2ObagnaFMnMhlejhaGxsk=";
meta = with lib; {
description = "Go tool to auto generate methods for enums";
homepage = "https://github.com/dmarkham/enumer";
license = licenses.bsd2;
maintainers = with maintainers; [ hexa ];
};
}

View file

@ -480,6 +480,8 @@ with pkgs;
efficient-compression-tool = callPackage ../tools/compression/efficient-compression-tool { };
enumer = callPackage ../tools/misc/enumer { };
evans = callPackage ../development/tools/evans { };
expressvpn = callPackage ../applications/networking/expressvpn { };
@ -6452,6 +6454,8 @@ with pkgs;
ettercap = callPackage ../applications/networking/sniffers/ettercap { };
evcc = callPackage ../servers/home-automation/evcc { };
eventstat = callPackage ../os-specific/linux/eventstat { };
evillimiter = python3Packages.callPackage ../tools/networking/evillimiter { };