Merge branch 'feature/flakes'
This commit is contained in:
commit
6dc18d06e1
298 changed files with 5865 additions and 4682 deletions
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"url": "https://github.com/NixOS/nixpkgs.git",
|
||||
"rev": "6bfe71f2a4e2e425dee26b25d2309f341ff1600d",
|
||||
"date": "2021-09-02T17:55:10+02:00",
|
||||
"path": "/nix/store/wmg7a97b7ql8kj413wkvh2pmvl5m4nkd-nixpkgs",
|
||||
"sha256": "1mpf700fqlzyj6vsy2c329zlgbk9g6giwiyb2g0yhc0a78h72g8l",
|
||||
"fetchSubmodules": false,
|
||||
"deepClone": false,
|
||||
"leaveDotGit": false
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"url": "https://github.com/NixOS/nixpkgs.git",
|
||||
"rev": "a51aa6523bd8ee985bc70987909eff235900197a",
|
||||
"date": "2021-09-04T10:19:48-03:00",
|
||||
"path": "/nix/store/qylkdn96ah6r3mhh5m0p3yv236nxdbsa-nixpkgs",
|
||||
"sha256": "1rpikl60v179gsshqfrr4xwz42db5g87scm2v2hk3v3jys9dqrgc",
|
||||
"fetchSubmodules": false,
|
||||
"deepClone": false,
|
||||
"leaveDotGit": false
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"url": "https://git.ingolf-wagner.de/krebs/krops.git",
|
||||
"rev": "2e93a93ac264a480b427acc2684993476732539d",
|
||||
"date": "2018-09-19T19:57:26+02:00",
|
||||
"sha256": "1s6b2cs60xa270ynhr32qj1rcy3prvf9pidap0qbbvgg008iafxk",
|
||||
"fetchSubmodules": false
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"url": "https://cgit.krebsco.de/nix-writers/",
|
||||
"rev": "fc8a3802a0777a5f43a9a2fe0f5848ecaeb555a1",
|
||||
"date": "2018-10-27T14:45:48+02:00",
|
||||
"path": "/nix/store/81f2li00frwb29kzk7wjw7b87l65s8bg-nix-writers",
|
||||
"sha256": "1iy207rcbz9nv9bf64025ypy38x8mwzl6snbmbrq347h6vvs0ksc",
|
||||
"fetchSubmodules": false,
|
||||
"deepClone": false,
|
||||
"leaveDotGit": false
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"url": "https://github.com/nix-community/nixos-generators.git",
|
||||
"rev": "ef1e4480cf8af45cfdeac597b2f1b1af33923e93",
|
||||
"date": "2019-01-18T10:41:01+01:00",
|
||||
"path": "/nix/store/61wmz4fvlyxnxhw9smkl897rhavj06ry-nixos-generators-ef1e448",
|
||||
"sha256": "0ymzp4pmpkjjjg5h8d45gv8avy4wh1dj0v238i2cz3jp3j489ik9",
|
||||
"fetchSubmodules": false,
|
||||
"deepClone": false,
|
||||
"leaveDotGit": false
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
{ pkgs, lib, config, ... }: {
|
||||
|
||||
services.mqtt.light-control.enable = true;
|
||||
services.mqtt.light-control.loglevel = "debug";
|
||||
services.mqtt.light-control.config = {
|
||||
credentials = {
|
||||
host = "tcp://localhost:1883";
|
||||
user = "homeassistant";
|
||||
password = "hallo";
|
||||
};
|
||||
scenes = [
|
||||
{
|
||||
name = "up-dark";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "half";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
disabled_switches = [
|
||||
"zigbee2mqtt/led_1"
|
||||
"zigbee2mqtt/led_2"
|
||||
"zigbee2mqtt/light_2"
|
||||
"zigbee2mqtt/light_4"
|
||||
"zigbee2mqtt/light_5"
|
||||
"zigbee2mqtt/light_7"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "down";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "up-bright";
|
||||
disabled_switches = [
|
||||
"zigbee2mqtt/led_1"
|
||||
"zigbee2mqtt/led_2"
|
||||
"zigbee2mqtt/light_2"
|
||||
"zigbee2mqtt/light_4"
|
||||
"zigbee2mqtt/light_5"
|
||||
"zigbee2mqtt/light_7"
|
||||
];
|
||||
ignored_sensors = [ "zigbee2mqtt/door_sensor_4" ];
|
||||
}
|
||||
{
|
||||
name = "outside";
|
||||
room_tracking_enabled = false;
|
||||
ignored_sensors = [ "zigbee2mqtt/door_sensor_4" ];
|
||||
}
|
||||
{
|
||||
name = "night";
|
||||
room_tracking_enabled = false;
|
||||
brightness = 25;
|
||||
ignored_sensors =
|
||||
[ "zigbee2mqtt/motion_sensor_7" "zigbee2mqtt/door_sensor_4" ];
|
||||
}
|
||||
];
|
||||
sensors = let
|
||||
door = { topic, room }: {
|
||||
topic = topic;
|
||||
key = "contact";
|
||||
room = room;
|
||||
invert_state = true;
|
||||
delay = 90;
|
||||
};
|
||||
motion = { topic, room }: {
|
||||
topic = topic;
|
||||
key = "occupancy";
|
||||
room = room;
|
||||
delay = 60;
|
||||
};
|
||||
in [
|
||||
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_1";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_2";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_6";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_8";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_7";
|
||||
room = "sleeping_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_5";
|
||||
room = "kitchen";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_4";
|
||||
room = "storage_room";
|
||||
})
|
||||
|
||||
(door {
|
||||
topic = "zigbee2mqtt/door_sensor_1";
|
||||
room = "storage_room";
|
||||
})
|
||||
(door {
|
||||
topic = "zigbee2mqtt/door_sensor_5";
|
||||
room = "sleeping_room";
|
||||
})
|
||||
(door {
|
||||
# house door
|
||||
topic = "zigbee2mqtt/door_sensor_4";
|
||||
room = "floor";
|
||||
})
|
||||
|
||||
];
|
||||
switches = let
|
||||
sonoff = { id, rooms, delay ? 0 }: {
|
||||
topic = "stat/${id}/RESULT";
|
||||
key = "POWER";
|
||||
rooms = rooms;
|
||||
delay = delay;
|
||||
command = {
|
||||
command = "{{state}}";
|
||||
init_command = "(null)";
|
||||
topic = "cmnd/${id}/POWER";
|
||||
on = "ON";
|
||||
off = "OFF";
|
||||
};
|
||||
};
|
||||
light = { topic, rooms, delay ? 0 }: {
|
||||
topic = topic;
|
||||
key = "state";
|
||||
rooms = rooms;
|
||||
delay = delay;
|
||||
command = {
|
||||
command = ''{"state":"{{state}}","brightness":{{brightness}}}'';
|
||||
topic = "${topic}/set";
|
||||
on = "ON";
|
||||
off = "OFF";
|
||||
};
|
||||
};
|
||||
led = { topic, rooms, delay ? 0 }: {
|
||||
topic = topic;
|
||||
key = "state";
|
||||
rooms = rooms;
|
||||
delay = delay;
|
||||
command = {
|
||||
# Configure it once to the color you like
|
||||
# {"state":"{{state}}","brightness":{{brightness}},"color":{"hex":"#FFFFFF},"color_temp":255","transition":0}
|
||||
command = ''
|
||||
{"state":"{{state}}","brightness":{{brightness}},"transition":0}'';
|
||||
topic = "${topic}/set";
|
||||
on = "ON";
|
||||
off = "OFF";
|
||||
};
|
||||
};
|
||||
in [
|
||||
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_2";
|
||||
rooms = [ "office_room" ];
|
||||
})
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_4";
|
||||
rooms = [ "office_room" ];
|
||||
})
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_5";
|
||||
rooms = [ "storage_room" ];
|
||||
})
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_7";
|
||||
rooms = [ "sleeping_room" ];
|
||||
})
|
||||
(led {
|
||||
topic = "zigbee2mqtt/led_1";
|
||||
rooms = [ "office_room" ];
|
||||
})
|
||||
(led {
|
||||
topic = "zigbee2mqtt/led_2";
|
||||
rooms = [ "kitchen" ];
|
||||
})
|
||||
|
||||
#(sonoff {
|
||||
# id = "PAL01";
|
||||
# rooms = [ "bed_room" ];
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL03";
|
||||
# rooms = [ "living_room" ];
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL04";
|
||||
# rooms = [ "bed_room" ];
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL06";
|
||||
# rooms = [ "kitchen" ];
|
||||
#})
|
||||
## monitor and speakers
|
||||
#(sonoff {
|
||||
# id = "PAL07";
|
||||
# rooms = [ "bed_room" ];
|
||||
# delay = 180;
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL08";
|
||||
# rooms = [ "bed_room" ];
|
||||
# delay = 180;
|
||||
#})
|
||||
|
||||
];
|
||||
};
|
||||
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
{ lib, config, pkgs, ... }:
|
||||
let
|
||||
|
||||
folderPath = config.services.home-assistant.configDir;
|
||||
|
||||
# find symbols with
|
||||
# https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords=<keywords>&apikey=<api_key>
|
||||
# as described here : https://www.alphavantage.co/documentation/#symbolsearch
|
||||
#
|
||||
# example:
|
||||
# --------
|
||||
# stocks = [
|
||||
# {
|
||||
# symbol = "GOOGL";
|
||||
# name = "google";
|
||||
# friendly_name = "Google";
|
||||
# currency = "$";
|
||||
# # I own 50 and bought at a price of 1000
|
||||
# own = {
|
||||
# pieces = 50;
|
||||
# price = 1000;
|
||||
# };
|
||||
# }
|
||||
# ];
|
||||
stocks = import <secrets/home-assistant/stocks>;
|
||||
filePath = name: "${folderPath}/stock_${name}.json";
|
||||
|
||||
cleanup_list = list: lib.filter (entry: entry != { }) (lib.flatten list);
|
||||
|
||||
in {
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
sensor = cleanup_list (map ({ name, currency, own ? { }, ... }: [
|
||||
{
|
||||
platform = "file";
|
||||
name = "stock_${name}";
|
||||
file_path = filePath name;
|
||||
value_template = "{{ value_json.price}} ${currency}";
|
||||
|
||||
}
|
||||
{
|
||||
platform = "file";
|
||||
name = "stock_${name}_change";
|
||||
file_path = filePath name;
|
||||
value_template = "{{ value_json.change}} ${currency}";
|
||||
|
||||
}
|
||||
{
|
||||
platform = "file";
|
||||
name = "stock_${name}_change_percent";
|
||||
file_path = filePath name;
|
||||
value_template = "{{ value_json.change_percent}} %";
|
||||
}
|
||||
(lib.optionalAttrs (own != { }) {
|
||||
platform = "file";
|
||||
name = "stock_${name}_profit";
|
||||
file_path = filePath name;
|
||||
value_template = ''
|
||||
{{ "{:,.2f}".format( value_json.price * ${toString own.pieces} - ${
|
||||
toString (own.pieces * own.price)
|
||||
} ) }} ${currency}'';
|
||||
})
|
||||
]) stocks);
|
||||
|
||||
homeassistant = {
|
||||
whitelist_external_dirs = [ folderPath ];
|
||||
customize = builtins.listToAttrs (cleanup_list (map
|
||||
({ name, own ? { }, ... }: [
|
||||
{
|
||||
name = "sensor.stock_${name}";
|
||||
value = {
|
||||
icon = "mdi:cash-usd-outline";
|
||||
friendly_name = "Price";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "sensor.stock_${name}_change";
|
||||
value = {
|
||||
icon = "mdi:radar";
|
||||
friendly_name = "Difference";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "sensor.stock_${name}_change_percent";
|
||||
value = {
|
||||
icon = "mdi:radar";
|
||||
friendly_name = "Percent";
|
||||
};
|
||||
}
|
||||
(lib.optionalAttrs (own != { }) {
|
||||
name = "sensor.stock_${name}_profit";
|
||||
value = {
|
||||
icon = "mdi:radar";
|
||||
friendly_name = "Profit";
|
||||
};
|
||||
})
|
||||
]) stocks));
|
||||
};
|
||||
|
||||
group = (builtins.listToAttrs (map
|
||||
({ name, friendly_name, own ? { }, ... }: {
|
||||
name = "stock_${name}";
|
||||
value = {
|
||||
name = "${friendly_name} Aktie";
|
||||
entities = [
|
||||
"sensor.stock_${name}"
|
||||
"sensor.stock_${name}_change"
|
||||
"sensor.stock_${name}_change_percent"
|
||||
] ++ (lib.optional (own != { }) "sensor.stock_${name}_profit");
|
||||
};
|
||||
}) stocks));
|
||||
|
||||
};
|
||||
|
||||
systemd.services = let
|
||||
pullService = { name, symbol, currency, ... }: {
|
||||
name = "pull_stock_${name}";
|
||||
value = {
|
||||
enable = true;
|
||||
before = [ "home-assistant.service" ];
|
||||
wantedBy = [ "home-assistant.service" ];
|
||||
serviceConfig = {
|
||||
User = "hass";
|
||||
Type = "oneshot";
|
||||
};
|
||||
description = "pull stock_${name} for homeassistant";
|
||||
script = ''
|
||||
SYMBOL="${symbol}"
|
||||
CURRENCY="${currency}"
|
||||
APIKEY=${
|
||||
lib.fileContents <secrets/home-assistant/alphavantage/apikey>
|
||||
}
|
||||
|
||||
${pkgs.curl}/bin/curl --location --silent \
|
||||
"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=$SYMBOL&apikey=$APIKEY" \
|
||||
| ${pkgs.jq}/bin/jq --compact-output \
|
||||
'.["Global Quote"] |
|
||||
{
|
||||
price: .["05. price"] | tonumber,
|
||||
currency: "'$CURRENCY'",
|
||||
change_percent: .["10. change percent"] | .[0:-1] | tonumber,
|
||||
change: .["09. change"] | tonumber,
|
||||
last_date: .["07. latest trading day"],
|
||||
}' \
|
||||
>> ${filePath name}
|
||||
|
||||
# old and stupid
|
||||
#${pkgs.curl}/bin/curl --location --silent \
|
||||
#"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=$SYMBOL&interval=5min&apikey=$APIKEY" \
|
||||
#| ${pkgs.jq}/bin/jq --compact-output \
|
||||
# '.["Time Series (5min)"] | to_entries | [ .[]
|
||||
# | { date : .key , value : .value["4. close"], currency: "'$CURRENCY'" } ]
|
||||
# | sort_by(.date) | reverse | .[0]' \
|
||||
'';
|
||||
};
|
||||
};
|
||||
in builtins.listToAttrs (map pullService stocks);
|
||||
|
||||
systemd.timers = let
|
||||
pullTimer = { name, ... }: {
|
||||
name = "pull_stock_${name}";
|
||||
value = {
|
||||
enable = true;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "hourly";
|
||||
Persistent = "true";
|
||||
};
|
||||
};
|
||||
};
|
||||
in builtins.listToAttrs (map pullTimer stocks);
|
||||
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# we create 3 input_boolean which get toggled by the 3 types of buttons pressed.
|
||||
# input_boolean.single_${name} : single click
|
||||
# input_boolean.double_${name} : double click
|
||||
# input_boolean.hold_${name} : hold
|
||||
# if you override these input (via states) you have to create the input yourself
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/WXKG12LM.html
|
||||
allDevices = {
|
||||
"button_a1" = {
|
||||
id = "0x00158d0002b04f65";
|
||||
#groups = [ "living_room" ];
|
||||
states.single = "input_boolean.situation_toggle";
|
||||
states.hold = "input_boolean.printer_toggle";
|
||||
states.double = "input_boolean.windows_up";
|
||||
};
|
||||
"button_a2" = {
|
||||
id = "0x00158d0002b04f09";
|
||||
#groups = [ "bed_room" ];
|
||||
states.single = "input_boolean.situation_toggle";
|
||||
states.hold = "input_boolean.printer_toggle";
|
||||
states.double = "input_boolean.windows_up";
|
||||
};
|
||||
"button_a3" = {
|
||||
id = "0x00158d0002b00e04";
|
||||
#groups = [ "bed_room" ];
|
||||
states.single = "input_boolean.situation_toggle";
|
||||
states.hold = "input_boolean.printer_toggle";
|
||||
states.double = "input_boolean.windows_up";
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define input_boolean
|
||||
# --------------------
|
||||
# which get toggled by the buttons
|
||||
input_boolean = let stripEmpty = lib.filter (a: a != { });
|
||||
in builtins.listToAttrs (stripEmpty (lib.flatten (lib.mapAttrsToList (name:
|
||||
{ states ? { }, ... }: [
|
||||
(lib.optionalAttrs (!lib.hasAttr "single" states) {
|
||||
name = "single_${name}";
|
||||
value = { icon = "mdi:toggle-switch"; };
|
||||
})
|
||||
(lib.optionalAttrs (!lib.hasAttr "double" states) {
|
||||
name = "double_${name}";
|
||||
value = { icon = "mdi:toggle-switch"; };
|
||||
})
|
||||
(lib.optionalAttrs (!lib.hasAttr "hold" states) {
|
||||
name = "hold_${name}";
|
||||
value = { icon = "mdi:toggle-switch"; };
|
||||
})
|
||||
]) allDevices)));
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList (name:
|
||||
{ ... }: [
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = name;
|
||||
icon = "mdi:toggle-switch";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
value_template = "{{ value_json.click }}";
|
||||
}
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
]) allDevices);
|
||||
|
||||
binary_sensor = lib.mapAttrsToList (name:
|
||||
{ ... }: {
|
||||
name = name;
|
||||
platform = "mqtt";
|
||||
device_class = "motion";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
payload_on = true;
|
||||
payload_off = false;
|
||||
value_template = "{{ value_json.occupancy }}";
|
||||
}) allDevices;
|
||||
|
||||
# create groups
|
||||
# -------------
|
||||
#group = let
|
||||
# # to have nice panels for every device
|
||||
# sensorGroups = lib.mapAttrs (name:
|
||||
# { states ? { }, ... }:
|
||||
# let
|
||||
# entityIds = { single ? "input_boolean.single_${name}"
|
||||
# , double ? "input_boolean.double_${name}"
|
||||
# , hold ? "input_boolean.hold_${name}", ... }: [
|
||||
# single
|
||||
# double
|
||||
# hold
|
||||
# ];
|
||||
# in {
|
||||
# entities = [ "sensor.${name}" ] ++ (entityIds states)
|
||||
# ++ [ "sensor.battery_${name}" "sensor.link_${name}" ];
|
||||
# }) allDevices;
|
||||
# # sort lights into given groups.
|
||||
# sortedInGroups = let
|
||||
# groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList (name:
|
||||
# { groups ? [ ], states ? { }, ... }:
|
||||
# map (groupName: {
|
||||
# "${groupName}" = if (lib.hasAttr "single" states) then
|
||||
# states.single
|
||||
# else
|
||||
# "input_boolean.single_${name}";
|
||||
# }) groups) allDevices));
|
||||
# in lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
#in sortedInGroups // sensorGroups // {
|
||||
# all_sensors.entities =
|
||||
# lib.mapAttrsToList (name: { ... }: "binary_sensor.${name}") allDevices;
|
||||
#};
|
||||
|
||||
# create automation
|
||||
# -----------------
|
||||
automation = let
|
||||
|
||||
# single click
|
||||
toggle_single_button_input = lib.mapAttrsToList (name:
|
||||
{ states ? { }, ... }:
|
||||
let
|
||||
entityId = if (lib.hasAttr "single" states) then
|
||||
states.single
|
||||
else
|
||||
"input_boolean.single_${name}";
|
||||
in {
|
||||
alias = "toggle single click ${name}";
|
||||
trigger = {
|
||||
platform = "mqtt";
|
||||
topic = "zigbee2mqtt/${name}";
|
||||
};
|
||||
condition = {
|
||||
condition = "template";
|
||||
value_template = ''{{ "single" == trigger.payload_json.click}}'';
|
||||
};
|
||||
action = {
|
||||
service = "input_boolean.toggle";
|
||||
data.entity_id = entityId;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
# double click
|
||||
toggle_double_button_input = lib.mapAttrsToList (name:
|
||||
{ states ? { }, ... }:
|
||||
let
|
||||
entityId = if (lib.hasAttr "double" states) then
|
||||
states.double
|
||||
else
|
||||
"input_boolean.double_${name}";
|
||||
in {
|
||||
alias = "toggle double click ${name}";
|
||||
trigger = {
|
||||
platform = "mqtt";
|
||||
topic = "zigbee2mqtt/${name}";
|
||||
};
|
||||
condition = {
|
||||
condition = "template";
|
||||
value_template = ''{{ "double" == trigger.payload_json.click}}'';
|
||||
};
|
||||
action = {
|
||||
service = "input_boolean.toggle";
|
||||
data.entity_id = entityId;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
# hold
|
||||
toggle_hold_button_input = lib.mapAttrsToList (name:
|
||||
{ states ? { }, ... }:
|
||||
let
|
||||
entityId = if (lib.hasAttr "hold" states) then
|
||||
states.hold
|
||||
else
|
||||
"input_boolean.hold_${name}";
|
||||
in {
|
||||
alias = "toggle hold ${name}";
|
||||
trigger = {
|
||||
platform = "mqtt";
|
||||
topic = "zigbee2mqtt/${name}";
|
||||
};
|
||||
condition = {
|
||||
condition = "template";
|
||||
value_template = ''{{ "hold" == trigger.payload_json.action}}'';
|
||||
};
|
||||
action = {
|
||||
service = "input_boolean.toggle";
|
||||
data.entity_id = entityId;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
in lib.flatten (toggle_single_button_input ++ toggle_double_button_input
|
||||
++ toggle_hold_button_input);
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/MCCGQ11LM.html
|
||||
allDevices = {
|
||||
"door_sensor_1" = { id = "0x00158d000312dc52"; };
|
||||
"door_sensor_2" = { id = "0x00158d000316d5bf"; };
|
||||
"door_sensor_3" = { id = "0x00158d0002f9516f"; };
|
||||
"door_sensor_4" = { id = "0x00158d00031383b9"; };
|
||||
"door_sensor_5" = { id = "0x00158d0003120d3e"; };
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList (name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
]) allDevices);
|
||||
|
||||
binary_sensor = lib.mapAttrsToList (name:
|
||||
{ ... }: {
|
||||
name = name;
|
||||
platform = "mqtt";
|
||||
device_class = "door";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
payload_on = false;
|
||||
payload_off = true;
|
||||
value_template = "{{ value_json.contact}}";
|
||||
}) allDevices;
|
||||
|
||||
# create groups
|
||||
# -------------
|
||||
group = let
|
||||
# to have nice panels for every device
|
||||
sensorGroups = lib.mapAttrs (name:
|
||||
{ ... }: {
|
||||
entities = [
|
||||
"binary_sensor.${name}"
|
||||
"sensor.battery_${name}"
|
||||
"sensor.link_${name}"
|
||||
];
|
||||
}) allDevices;
|
||||
# sort lights into given groups.
|
||||
sortedInGroups = let
|
||||
groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList (name:
|
||||
{ groups ? [ ], ... }:
|
||||
map (groupName: { "${groupName}" = "binary_sensor.${name}"; }) groups)
|
||||
allDevices));
|
||||
in lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
in sortedInGroups // sensorGroups // {
|
||||
all_sensors.entities =
|
||||
lib.mapAttrsToList (name: { ... }: "binary_sensor.${name}") allDevices;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/E1757.html
|
||||
allDevices = {
|
||||
"office_fyrtur_1" = { id = "0x680ae2fffe64fa40"; };
|
||||
"office_fyrtur_2" = { id = "0x680ae2fffe91d234"; };
|
||||
"bedroom_fyrtur_1" = { id = "0x680ae2fffe6e9f41"; };
|
||||
"broken_fyrtur_1" = { id = "0x680ae2fffe8f6411"; };
|
||||
};
|
||||
|
||||
# -t "zigbee2mqtt/fyrtur1/set" -m '{"position":100}'
|
||||
# -t "zigbee2mqtt/fyrtur1/set" -m '{"position":15}'
|
||||
in {
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
transition = 0.1;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
sensor = lib.flatten (lib.mapAttrsToList (name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
]) allDevices);
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/SPZB0001.html
|
||||
allDevices = {
|
||||
"office_heater_1" = { id = "0x00158d00032f5ee4"; }; # office
|
||||
"office_heater_2" = { id = "0x00158d00032f5f9f"; }; # office (kitchen)
|
||||
"bedroom_heater_1" = { id = "0x00158d00032f6d1e"; }; # bed room
|
||||
"storage_heater_1" = { id = "0x00158d00032f604d"; }; # abstell raum
|
||||
};
|
||||
|
||||
# -t "zigbee2mqtt/heater3/set" -m '{"system_mode":"auto","current_heating_setpoint":23}'
|
||||
# -t "zigbee2mqtt/heater3/set" -m '{"system_mode":"off"}'
|
||||
|
||||
in {
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
legacy = false;
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
transition = 1;
|
||||
debounce = 0.5;
|
||||
filtered_attributes = [
|
||||
"battery_low"
|
||||
"eurotronic_host_flags"
|
||||
"eurotronic_system_mode"
|
||||
#"occupied_heating_setpoint"
|
||||
#"pi_heating_demand"
|
||||
#"unoccupied_heating_setpoint"
|
||||
];
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
sensor = lib.flatten (lib.mapAttrsToList (name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = "temperature_${name}";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "°C";
|
||||
device_class = "temperature";
|
||||
value_template = "{{ value_json.local_temperature }}";
|
||||
}
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = "pi_heating_demand_${name}";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
value_template = "{{ value_json.pi_heating_demand }}";
|
||||
}
|
||||
]) allDevices);
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/GL-C-007-1ID.html
|
||||
allDevices = {
|
||||
"led_1" = { id = "0x00124b001f7a5be9"; };
|
||||
"led_2" = { id = "0x00124b001ee958b3"; };
|
||||
};
|
||||
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"ON","transition":0, "color_temp":255}'
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"OFF","transition":0, "color_temp":255}'
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"ON","brightness":255,"color":{"hex":"#00FFFF"}}'
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"OFF"}'
|
||||
in {
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
transition = 1;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
light = lib.mapAttrsToList (name:
|
||||
{ ... }: {
|
||||
platform = "mqtt";
|
||||
name = name;
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
command_topic = "zigbee2mqtt/${name}/set";
|
||||
value_template = "{{ value_json.click }}";
|
||||
brightness = true;
|
||||
color_temp = true;
|
||||
schema = "json";
|
||||
}) allDevices;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/RTCGQ01LM.html
|
||||
allDevices = {
|
||||
|
||||
"motion_sensor_1" = { id = "0x00158d0002fbd451"; };
|
||||
"motion_sensor_2" = { id = "0x00158d0002f9a6b8"; };
|
||||
"motion_sensor_3" = { id = "0x00158d0002f04522"; };
|
||||
"motion_sensor_4" = { id = "0x00158d0002f9a558"; };
|
||||
"motion_sensor_5" = { id = "0x00158d0002f9a56f"; };
|
||||
"motion_sensor_6" = { id = "0x00158d0002f9a5cb"; };
|
||||
"motion_sensor_7" = { id = "0x00158d0002f9a6aa"; };
|
||||
"motion_sensor_8" = { id = "0x00158d0002f04637"; };
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
{ id, timeout ? 65, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
# should not be set below 60 seconds
|
||||
occupancy_timeout = timeout;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define meta information sensors
|
||||
binary_sensor = lib.flatten (lib.mapAttrsToList (name:
|
||||
{ ... }: [{
|
||||
name = "${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
value_template = "{{ value_json.occupancy }}";
|
||||
#icon = "mdi:battery-10";
|
||||
payload_on = true;
|
||||
payload_off = false;
|
||||
device_class = "motion";
|
||||
}]) allDevices);
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList (name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
]) allDevices);
|
||||
};
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/WSDCGQ11LM.html
|
||||
allDevices = {
|
||||
"temperature_sensor_1" = {
|
||||
id = "0x00158d0002d79220";
|
||||
groups = [ "living_room" ];
|
||||
};
|
||||
"temperature_sensor_2" = {
|
||||
id = "0x00158d0002d7913d";
|
||||
groups = [ "living_room" ];
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
};
|
||||
}) allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList (name:
|
||||
{ ... }: [
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = name;
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "°C";
|
||||
device_class = "temperature";
|
||||
value_template = "{{ value_json.temperature }}";
|
||||
}
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = "humidity_${name}";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
device_class = "humidity";
|
||||
value_template = "{{ value_json.humidity }}";
|
||||
}
|
||||
#{
|
||||
# platform = "mqtt";
|
||||
# name = "pressure_${name}";
|
||||
# state_topic = "zigbee2mqtt/${name}";
|
||||
# availability_topic = "zigbee2mqtt/bridge/state";
|
||||
# unit_of_measurement = "hPa";
|
||||
# device_class = "pressure";
|
||||
# value_template = "{{ value_json.pressure }}";
|
||||
#}
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
]) allDevices);
|
||||
|
||||
# create groups
|
||||
# -------------
|
||||
#group = let
|
||||
# # to have nice panels for every device
|
||||
# sensorGroups = lib.mapAttrs (name:
|
||||
# { ... }: {
|
||||
# entities = [
|
||||
# "sensor.${name}"
|
||||
# "sensor.humidity_${name}"
|
||||
# #"sensor.pressure_${name}"
|
||||
# "sensor.battery_${name}"
|
||||
# "sensor.link_${name}"
|
||||
# ];
|
||||
# }) allDevices;
|
||||
# # sort lights into given groups.
|
||||
# sortedInGroups = let
|
||||
# groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList (name:
|
||||
# { groups ? [ ], ... }:
|
||||
# map (groupName: { "${groupName}" = "sensor.${name}"; }) groups)
|
||||
# allDevices));
|
||||
# in lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
#in sortedInGroups // sensorGroups // {
|
||||
# all_sensors.entities =
|
||||
# lib.mapAttrsToList (name: { ... }: "sensor.${name}") allDevices;
|
||||
#};
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
let port = 8000;
|
||||
in {
|
||||
|
||||
# configure nginx
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts = {
|
||||
"paste.workhorse.private" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:${toString port}";
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host:$server_port;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 90;
|
||||
proxy_redirect http://localhost:${
|
||||
toString port
|
||||
} https://paste.workhorse.private/;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
krops.userKeys."bepasty" = {
|
||||
user = "bepasty";
|
||||
source = toString <secrets/bepasty-secret-key>;
|
||||
requiredBy = [ "bepasty-server-ingolf-wagner.de-gunicorn.service" ];
|
||||
};
|
||||
|
||||
services.bepasty = {
|
||||
enable = true;
|
||||
servers."ingolf-wagner.de" = {
|
||||
bind = "0.0.0.0:${toString port}";
|
||||
secretKeyFile = config.krops.userKeys."bepasty".target;
|
||||
extraConfig = ''
|
||||
PERMISSIONS = {
|
||||
'${
|
||||
lib.fileContents <common_secrets/bepasty/admin-password>
|
||||
}': 'admin,list,create,read,delete',
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
library = import <library> { inherit pkgs lib; };
|
||||
|
||||
sync-repo = library.jenkins.syncJob;
|
||||
job = library.jenkins.job;
|
||||
|
||||
in {
|
||||
|
||||
environment.systemPackages = [ pkgs.cabal-install ];
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts = {
|
||||
"jenkins.${config.networking.hostName}.private" = {
|
||||
locations."/" = {
|
||||
proxyPass =
|
||||
"http://localhost:${toString config.services.jenkins.port}";
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host:$server_port;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_read_timeout 90;
|
||||
proxy_redirect http://localhost:${
|
||||
toString config.services.jenkins.port
|
||||
} https://jenkins.${config.networking.hostName}.private/;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
krops.userKeys."accessToken" = {
|
||||
user = "jenkins";
|
||||
source = toString <secrets/jenkins/accessToken>;
|
||||
requiredBy = [ "jenkins-job-builder.service" ];
|
||||
};
|
||||
|
||||
services.jenkins = {
|
||||
enable = true;
|
||||
home = "/home/jenkins";
|
||||
port = 10420;
|
||||
|
||||
# Plugins to Install:
|
||||
# - all the plugins recommended at the setup
|
||||
# - Build pipeline
|
||||
# - SSH Agent
|
||||
# - mattermost plugin
|
||||
jobBuilder = {
|
||||
enable = true;
|
||||
|
||||
# create an access token in the admin users panel
|
||||
accessTokenFile = config.krops.userKeys."accessToken".target;
|
||||
accessUser = "admin";
|
||||
|
||||
# https://docs.openstack.org/infra/jenkins-job-builder/definition.html#modules
|
||||
nixJobs = let
|
||||
# ssh username + key
|
||||
gogs-id = "bc584c99-0fb7-43fb-af75-4076d64c51b2";
|
||||
# ssh username + key
|
||||
github-id = "bc584c99-0fb7-43fb-af75-4076d64c51b2";
|
||||
# ssh username + key
|
||||
sshSputnik = "d91eb57c-5bff-434c-b317-68aad46848d7";
|
||||
|
||||
sync-to-github = name: source: target:
|
||||
sync-repo name {
|
||||
url = source;
|
||||
credentialsId = gogs-id;
|
||||
} {
|
||||
url = target;
|
||||
credentialsId = github-id;
|
||||
};
|
||||
|
||||
in [
|
||||
|
||||
(job "sync-retiolum" {
|
||||
url = "git@github.com:krebs/retiolum.git";
|
||||
credentialsId = github-id;
|
||||
triggers = [{ timed = "H/30 * * * *"; }];
|
||||
} [
|
||||
{
|
||||
"Download Files" = [
|
||||
"chmod 755 hosts"
|
||||
"chmod 755 -R hosts"
|
||||
''
|
||||
nix-shell -p curl -p gnutar -p bzip2 --run "curl https://lassul.us/retiolum-hosts.tar.bz2 | tar xvjf - || true"''
|
||||
"chmod 755 -R etc.hosts"
|
||||
''
|
||||
nix-shell -p curl --run "curl https://lassul.us/retiolum.hosts > etc.hosts || true"''
|
||||
];
|
||||
}
|
||||
{
|
||||
"update repo" = [
|
||||
''nix-shell -p git --run "git add ."''
|
||||
''
|
||||
nix-shell -p git --run "git -c user.name=\'Ingolf Wagner\' -c user.email=\'contact@ingolf-wagner.de\' commit -m update-`date +%Y-%m-%dT%H:%M:%S` || exit 0"''
|
||||
];
|
||||
}
|
||||
{
|
||||
Push = [{
|
||||
script = ''nix-shell -p git --run "git push origin master"'';
|
||||
credentialsId = github-id;
|
||||
}];
|
||||
}
|
||||
])
|
||||
|
||||
(job "test-taskninja" {
|
||||
url = "ssh://gogs@workhorse.private:2222/palo/taskninja.git";
|
||||
credentialsId = gogs-id;
|
||||
} [
|
||||
{
|
||||
"Create Shell" = [
|
||||
''
|
||||
nix-shell -p cabal2nix --run "cabal2nix --shell file://. > jenkins.nix"''
|
||||
];
|
||||
}
|
||||
{ Update = [ ''nix-shell ./jenkins.nix --run "cabal update"'' ]; }
|
||||
{
|
||||
Configure = [
|
||||
''nix-shell ./jenkins.nix --run "cabal configure --enable-tests"''
|
||||
''
|
||||
nix-shell ./jenkins.nix --run "cabal install --only-dependencies"''
|
||||
];
|
||||
}
|
||||
{ Build = [ ''nix-shell ./jenkins.nix --run "cabal build"'' ]; }
|
||||
{ Test = [ ''nix-shell ./jenkins.nix --run "cabal test"'' ]; }
|
||||
])
|
||||
|
||||
# sync to github
|
||||
# --------------
|
||||
(sync-to-github "sync-radiodj"
|
||||
"ssh://gogs@workhorse.private:2222/crashburn_radio/radio-dj2.git"
|
||||
"git@github.com:crashburn-radio/radio-dj.git")
|
||||
(sync-to-github "sync-radiodj-tracks"
|
||||
"ssh://gogs@workhorse.private:2222/crashburn_radio/radio-dj-tracks.git"
|
||||
"git@github.com:crashburn-radio/radio-dj-tracks.git")
|
||||
|
||||
(sync-to-github "sync-krops-module"
|
||||
"ssh://gogs@workhorse.private:2222/nix-modules/krops.git"
|
||||
"git@github.com:mrVanDalo/module.krops.git")
|
||||
|
||||
(sync-to-github "sync-cluster-module"
|
||||
"ssh://gogs@workhorse.private:2222/nix-modules/cluster.git"
|
||||
"git@github.com:mrVanDalo/module.cluster.git")
|
||||
|
||||
(sync-to-github "sync-backup-module"
|
||||
"ssh://gogs@workhorse.private:2222/nix-modules/backup.git"
|
||||
"git@github.com:mrVanDalo/module.backup.git")
|
||||
|
||||
(sync-to-github "sync-module-tinc"
|
||||
"ssh://gogs@workhorse.private:2222/palo/nixos-tinc.git"
|
||||
"git@github.com:mrVanDalo/nixos-tinc.git")
|
||||
|
||||
(sync-to-github "sync-memo"
|
||||
"ssh://gogs@workhorse.private:2222/palo/memo.git"
|
||||
"git@github.com:mrVanDalo/memo.git")
|
||||
|
||||
(sync-to-github "sync-diagrams-template"
|
||||
"ssh://gogs@workhorse.private:2222/palo/diagrams-template.git"
|
||||
"git@github.com:mrVanDalo/diagrams.git")
|
||||
|
||||
(sync-to-github "sync-plops"
|
||||
"ssh://gogs@workhorse.private:2222/palo/plops.git"
|
||||
"git@github.com:mrVanDalo/plops.git")
|
||||
|
||||
(sync-to-github "sync-image-generator"
|
||||
"ssh://gogs@workhorse.private:2222/palo/image-generator2.git"
|
||||
"git@github.com:mrVanDalo/image-generator.git")
|
||||
|
||||
(sync-to-github "sync-image-generator-lib"
|
||||
"ssh://gogs@workhorse.private:2222/palo/image-generator-lib.git"
|
||||
"git@github.com:mrVanDalo/image-generator-examples.git")
|
||||
|
||||
(sync-to-github "sync-tech.ingolf-wagner.de"
|
||||
"ssh://gogs@workhorse.private:2222/palo/tech.ingolf-wagner.de.git"
|
||||
"git@github.com:mrVanDalo/tech.ingolf-wagner.de.git")
|
||||
|
||||
(sync-to-github "sync-LineageOS-build"
|
||||
"ssh://gogs@git.ingolf-wagner.de:443/palo/LineagoOS-build.git"
|
||||
"git@github.com:mrVanDalo/LineagoOS-build.git")
|
||||
|
||||
(sync-to-github "sync-http-errors"
|
||||
"ssh://gogs@git.ingolf-wagner.de:443/palo/http-errors.git"
|
||||
"git@github.com:mrVanDalo/http-errors.git")
|
||||
(sync-to-github "sync-light-control"
|
||||
"ssh://gogs@git.ingolf-wagner.de:443/palo/light-control.git"
|
||||
"git@github.com:mrVanDalo/light-control.git")
|
||||
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
hostAddress = "192.168.100.20";
|
||||
containerAddress = "192.168.100.21";
|
||||
|
||||
in {
|
||||
|
||||
# backup mattermost
|
||||
backup.dirs = [ "/home/mattermost" ];
|
||||
|
||||
containers.mattermost = {
|
||||
|
||||
# mount host folders
|
||||
bindMounts = {
|
||||
home = {
|
||||
# make sure this folder exist on the host
|
||||
hostPath = toString "/home/mattermost/home";
|
||||
mountPoint = "/var/lib/mattermost";
|
||||
isReadOnly = false;
|
||||
};
|
||||
db = {
|
||||
# make sure this folder exist on the host
|
||||
hostPath = toString "/home/mattermost/db";
|
||||
mountPoint = "/var/lib/postgresql";
|
||||
isReadOnly = false;
|
||||
};
|
||||
};
|
||||
|
||||
# container network setup
|
||||
# see also nating on host system.
|
||||
privateNetwork = true;
|
||||
hostAddress = hostAddress;
|
||||
localAddress = containerAddress;
|
||||
|
||||
autoStart = true;
|
||||
|
||||
config = { config, pkgs, lib, ... }: {
|
||||
|
||||
imports = [ <modules> <krops-lib> ];
|
||||
|
||||
services.nginx = {
|
||||
|
||||
# Use recommended settings
|
||||
recommendedGzipSettings = lib.mkDefault true;
|
||||
recommendedOptimisation = lib.mkDefault true;
|
||||
recommendedProxySettings = lib.mkDefault true;
|
||||
recommendedTlsSettings = lib.mkDefault true;
|
||||
|
||||
# for graylog logging
|
||||
commonHttpConfig = let
|
||||
access_log_sink = "${hostAddress}:12304";
|
||||
error_log_sink = "${hostAddress}:12305";
|
||||
in ''
|
||||
log_format graylog2_json escape=json '{ "timestamp": "$time_iso8601", '
|
||||
'"facility": "nginx", '
|
||||
'"src_addr": "$remote_addr", '
|
||||
'"body_bytes_sent": $body_bytes_sent, '
|
||||
'"request_time": $request_time, '
|
||||
'"response_status": $status, '
|
||||
'"request": "$request", '
|
||||
'"request_method": "$request_method", '
|
||||
'"host": "$host",'
|
||||
'"upstream_cache_status": "$upstream_cache_status",'
|
||||
'"upstream_addr": "$upstream_addr",'
|
||||
'"http_x_forwarded_for": "$http_x_forwarded_for",'
|
||||
'"http_referrer": "$http_referer", '
|
||||
'"http_user_agent": "$http_user_agent" }';
|
||||
|
||||
access_log syslog:server=${access_log_sink} graylog2_json;
|
||||
error_log syslog:server=${error_log_sink};
|
||||
'';
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8065 6667 ];
|
||||
networking.firewall.allowedUDPPorts = [ 8065 ];
|
||||
|
||||
# setup matter most
|
||||
services.mattermost = {
|
||||
enable = true;
|
||||
siteUrl = "https://chat.ingolf-wagner.de";
|
||||
localDatabaseName = "chat";
|
||||
localDatabaseUser = "chatty";
|
||||
listenAddress = ":8065";
|
||||
|
||||
matterircd = {
|
||||
enable = true;
|
||||
parameters = [
|
||||
"-mmserver chat.ingolf-wagner.de"
|
||||
"-restrict chat.ingolf-wagner.de"
|
||||
"-bind [::]:6667"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# send log to host systems graylog (use tinc or wireguard if host is not graylog)
|
||||
services.SystemdJournal2Gelf.enable = true;
|
||||
services.SystemdJournal2Gelf.graylogServer = "${hostAddress}:11201";
|
||||
|
||||
services.journald.extraConfig = "SystemMaxUse=1G";
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
# give containers internet access
|
||||
networking.nat.enable = true;
|
||||
networking.nat.internalInterfaces = [ "ve-mattermost" ];
|
||||
networking.nat.externalInterface = "enp2s0f1";
|
||||
|
||||
# don't let networkmanager manger container network
|
||||
networking.networkmanager.unmanaged = [ "interface-name:ve-*" ];
|
||||
|
||||
# open ports for logging
|
||||
networking.firewall.interfaces."ve-mattermost".allowedTCPPorts =
|
||||
[ 11201 12304 12305 ];
|
||||
networking.firewall.interfaces."ve-mattermost".allowedUDPPorts =
|
||||
[ 11201 12304 12305 ];
|
||||
|
||||
# host nginx setup
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
"chat.workhorse.private" = {
|
||||
serverAliases = [ "chat.ingolf-wagner.de" ];
|
||||
locations."/" = {
|
||||
proxyWebsockets = true;
|
||||
proxyPass = "http://${containerAddress}:8065";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{ config, pkgs, ... }:
|
||||
let unstable = import <nixpkgs-unstable> { };
|
||||
in { environment.systemPackages = with pkgs; [ ]; }
|
77
flake.lock
Normal file
77
flake.lock
Normal file
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1597053966,
|
||||
"narHash": "sha256-f9lbPS/GJ1His8fsDqM6gfa8kSqREU4eKiMCS5hrKg4=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ec20f52e2ff61e9c36c2b894b62fc1b4bd04c71b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"krops": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1632420452,
|
||||
"narHash": "sha256-ncK6vABW/Ku9XI0kqj1otarUfblryoQzSaOCnaZ0oSs=",
|
||||
"owner": "Mic92",
|
||||
"repo": "krops",
|
||||
"rev": "0388970c568905fedcbf429e5745aacd4f7a6633",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Mic92",
|
||||
"repo": "krops",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1635070614,
|
||||
"narHash": "sha256-eRup9WsvSIhsRrSlNugPcQ7gfGOsbk3d4izufwVlz1Q=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3b1789322fcbcb5cf51228d732752714f1bf77da",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-21.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"krops": "krops",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"secrets": "secrets"
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-tsXsKNsa6/AqhXV6YxsSweX++YlwzQuWt0KeaV3SMgQ=",
|
||||
"path": "/home/palo/dev/secrets",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"path": "/home/palo/dev/secrets",
|
||||
"type": "path"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
31
flake.nix
Normal file
31
flake.nix
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
|
||||
description = "my krops file";
|
||||
|
||||
inputs = {
|
||||
secrets = {
|
||||
url = "path:/home/palo/dev/secrets";
|
||||
flake = false;
|
||||
};
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-21.05";
|
||||
krops = {
|
||||
url = "github:Mic92/krops";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, krops, secrets, ... }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
writeCommand = krops.packages.${system}.writeCommand;
|
||||
in
|
||||
{
|
||||
# deploy like this:
|
||||
# nix run ".#deploy.sterni"
|
||||
apps.${system}.deploy = pkgs.callPackage ./nixos/krops.nix {
|
||||
inherit writeCommand secrets;
|
||||
lib = krops.lib;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
{ lib, ... }:
|
||||
|
||||
with builtins;
|
||||
|
||||
# https://jenkinsci.github.io/job-dsl-plugin/
|
||||
|
||||
{
|
||||
# source container url and credentialsId
|
||||
job = name:
|
||||
{ url, credentialsId, branch ? "master",
|
||||
# https://docs.openstack.org/infra/jenkins-job-builder/triggers.html
|
||||
triggers ? [{
|
||||
pollscm = {
|
||||
cron = "H/30 * * * *";
|
||||
ignore-post-commit-hooks = true;
|
||||
};
|
||||
}], ... }:
|
||||
config: {
|
||||
job = {
|
||||
inherit name triggers;
|
||||
sandbox = true;
|
||||
project-type = "pipeline";
|
||||
dsl = let
|
||||
stage = elem:
|
||||
let
|
||||
stageName = head (attrNames elem);
|
||||
stateScripts = map (stage:
|
||||
lib.getAttr (typeOf stage) {
|
||||
string = ''
|
||||
withEnv(['PATH=/run/current-system/sw/bin/','NIX_PATH=/var/src/']) {
|
||||
sh '${toString stage}'
|
||||
}'';
|
||||
set = let
|
||||
script = ''
|
||||
withEnv(['PATH=/run/current-system/sw/bin/','NIX_PATH=/var/src/']) {
|
||||
sh '${toString stage.script}'
|
||||
}
|
||||
'';
|
||||
in if (stage.credentialsId != null) then ''
|
||||
sshagent(['${stage.credentialsId}']) { ${script} }
|
||||
'' else
|
||||
script;
|
||||
}) (getAttr stageName elem);
|
||||
in ''
|
||||
stage('${stageName}') {
|
||||
steps {
|
||||
${concatStringsSep "\n" stateScripts}
|
||||
}
|
||||
}
|
||||
'';
|
||||
stages = map stage config;
|
||||
in ''
|
||||
pipeline {
|
||||
agent any
|
||||
post {
|
||||
failure {
|
||||
mattermostSend channel: 'notification', color: '#FF0000', message: "Failed to build : [''${env.JOB_NAME}-''${env.BUILD_NUMBER}](''${env.BUILD_URL})"
|
||||
}
|
||||
success {
|
||||
mattermostSend channel: 'jenkins', color: '#00FF00', message: "Successfully build : [''${env.JOB_NAME}-''${env.BUILD_NUMBER}](''${env.JOB_URL})"
|
||||
}
|
||||
}
|
||||
stages{
|
||||
stage('Pull') {
|
||||
steps {
|
||||
checkout(
|
||||
[$class: 'GitSCM'
|
||||
, branches: [[name: '*/${branch}']]
|
||||
, doGenerateSubmoduleConfigurations: false
|
||||
, extensions: [[$class: 'LocalBranch', localBranch: 'master']]
|
||||
, submoduleCfg: []
|
||||
, userRemoteConfigs:
|
||||
[[ credentialsId: '${credentialsId}'
|
||||
, url: '${url}']]
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
${concatStringsSep "\n" stages}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# creates a sync job
|
||||
# source and target container url and credentialsId
|
||||
syncJob = name: source: target: {
|
||||
job = {
|
||||
name = name;
|
||||
sandbox = true;
|
||||
project-type = "pipeline";
|
||||
triggers = [{
|
||||
pollscm = {
|
||||
cron = "H/30 * * * *";
|
||||
ignore-post-commit-hooks = true;
|
||||
};
|
||||
}];
|
||||
dsl = ''
|
||||
pipeline {
|
||||
agent any
|
||||
post {
|
||||
failure {
|
||||
mattermostSend channel: 'notification', color: '#FF0000', message: "Failed to build : [''${env.JOB_NAME}-''${env.BUILD_NUMBER}](''${env.BUILD_URL})"
|
||||
}
|
||||
success {
|
||||
mattermostSend channel: 'jenkins', color: '#00FF00', message: "Successfully build : [''${env.JOB_NAME}-''${env.BUILD_NUMBER}](''${env.JOB_URL})"
|
||||
}
|
||||
}
|
||||
stages{
|
||||
stage('Pull') {
|
||||
steps {
|
||||
checkout(
|
||||
[$class: 'GitSCM'
|
||||
, branches: [[name: '*/master']]
|
||||
, doGenerateSubmoduleConfigurations: false
|
||||
, extensions: [[$class: 'LocalBranch', localBranch: 'master']]
|
||||
, submoduleCfg: []
|
||||
, userRemoteConfigs:
|
||||
[[ credentialsId: '${source.credentialsId}'
|
||||
, url: '${source.url}']]
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
stage('Push') {
|
||||
steps {
|
||||
sshagent(['${target.credentialsId}']) {
|
||||
withEnv(['PATH=/run/current-system/sw/bin/','NIX_PATH=/var/src/']) {
|
||||
sh "git push -f ${target.url}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Push Tags') {
|
||||
steps {
|
||||
sshagent(['${target.credentialsId}']) {
|
||||
withEnv(['PATH=/run/current-system/sw/bin/']) {
|
||||
sh "git push -f ${target.url} --tags"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.custom.video;
|
||||
|
||||
# show keyboard input on desktop for screencasts
|
||||
screenKey = pkgs.symlinkJoin {
|
||||
name = "screen-keys";
|
||||
paths = let
|
||||
screenKeyScript = { position ? "bottom", size ? "small", ... }:
|
||||
pkgs.writeShellScriptBin "screenkeys-${position}-${size}" # sh
|
||||
''
|
||||
${pkgs.screenkey}/bin/screenkey \
|
||||
--no-detach \
|
||||
--bg-color '#fdf6e3' \
|
||||
--font-color '#073642' \
|
||||
-p ${position} \
|
||||
-s ${size} \
|
||||
"$@"
|
||||
'';
|
||||
in lib.flatten (lib.flip map [ "large" "small" "medium" ] (size:
|
||||
lib.flip map [ "top" "center" "bottom" ]
|
||||
(position: screenKeyScript { inherit size position; })));
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
options.programs.custom.video.enable = mkEnableOption "enable video tools";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = with pkgs; [
|
||||
youtube-dl
|
||||
mplayer
|
||||
mpv
|
||||
|
||||
# to record your screen
|
||||
# ---------------------
|
||||
simplescreenrecorder
|
||||
screenKey
|
||||
|
||||
# to transcode video material
|
||||
# ---------------------------
|
||||
handbrake
|
||||
ffmpeg-full
|
||||
|
||||
# video editing
|
||||
# -------------
|
||||
openshot-qt
|
||||
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
@ -1,399 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.custom.vim;
|
||||
|
||||
nix-xptemplates = pkgs.writeTextFile {
|
||||
name = "nix-xptemplates";
|
||||
destination = "/ftplugin/nix/nix.xpt.vim";
|
||||
text = # vim
|
||||
''
|
||||
XPTemplate priority=personal
|
||||
|
||||
XPT option " tips
|
||||
`name^ = mkOption {
|
||||
type = with types; `type^;
|
||||
description = ${"''"}
|
||||
`cursor^
|
||||
${"''"};
|
||||
};
|
||||
|
||||
XPT package " tips
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
`cursor^
|
||||
}
|
||||
|
||||
XPT terranix" tips
|
||||
{ config, lib, pkgs, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.`name^;
|
||||
in {
|
||||
|
||||
options.`name^ = mkOption {
|
||||
default = {};
|
||||
type = with types; attrsOf (submodule ({ name, ... }:{
|
||||
options = {
|
||||
enable = mkEnableOption "`name^.name";
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
allConfigs = cfg
|
||||
in
|
||||
mkIf (cfg != {} ){
|
||||
`cursor^
|
||||
};
|
||||
}
|
||||
|
||||
XPT module " tips
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.`name^;
|
||||
|
||||
in {
|
||||
|
||||
options.`name^ = {
|
||||
enable = mkEnableOption "enable `name^";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
`cursor^
|
||||
};
|
||||
}
|
||||
|
||||
XPT shell " tips
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
|
||||
# needed pkgs
|
||||
# -----------
|
||||
buildInputs = with pkgs; [
|
||||
`name^
|
||||
];
|
||||
|
||||
# run this on start
|
||||
# -----------------
|
||||
shellHook = ${"''"}
|
||||
HISTFILE=${"$"}{toString ./.}/.history
|
||||
${"''"};
|
||||
}
|
||||
|
||||
XPT fhsUser " tips
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
(pkgs.buildFHSUserEnv {
|
||||
name = "fhs-user-env";
|
||||
|
||||
targetPkgs = pkgs: with pkgs; [
|
||||
# core stuff
|
||||
# ----------
|
||||
vim silver-searcher curl coreutils git tig
|
||||
|
||||
# common X dependencies
|
||||
# ---------------------
|
||||
atk cairo dbus eudev expat fontconfig freetype gdk_pixbuf glib gnome3.GConf gtk2-x11
|
||||
mesa_glu nspr nss pango xlibs.libXScrnSaver xlibs.libXcomposite xlibs.libXcursor
|
||||
xlibs.libXdamage xlibs.libXfixes xlibs.libXi xlibs.libXrender xlibs.libXtst xorg.libX11
|
||||
xorg.libXext xorg.libXinerama xorg.libxcb
|
||||
liblo zlib fftw minixml libcxx alsaLib glibc
|
||||
|
||||
# new stuff
|
||||
# ---------
|
||||
`cursor^
|
||||
|
||||
];
|
||||
|
||||
# multilib packages
|
||||
# -----------------
|
||||
# these are packages compiled 32bit and 64bit
|
||||
multiPkgs = pkgs: with pkgs; [
|
||||
];
|
||||
|
||||
# environment variables
|
||||
# ---------------------
|
||||
profile = ${"''"}
|
||||
export TERM="xterm"
|
||||
${"''"};
|
||||
|
||||
}).env
|
||||
|
||||
'';
|
||||
};
|
||||
|
||||
vim-tv-plugin = with lib;
|
||||
((rtp: rtp // { inherit rtp; }) (pkgs.write "vim-tv" {
|
||||
"/syntax/haskell.vim".text = # vim
|
||||
''
|
||||
syn region String start=+\[[[:alnum:]]*|+ end=+|]+
|
||||
|
||||
hi link ConId Identifier
|
||||
hi link VarId Identifier
|
||||
hi link hsDelimiter Delimiter
|
||||
'';
|
||||
"/syntax/nix.vim".text = # vim
|
||||
''
|
||||
"" Quit when a (custom) syntax file was already loaded
|
||||
"if exists("b:current_syntax")
|
||||
" finish
|
||||
"endif
|
||||
|
||||
"setf nix
|
||||
|
||||
" Ref <nix/src/libexpr/lexer.l>
|
||||
syn match NixID /[a-zA-Z\_][a-zA-Z0-9\_\'\-]*/
|
||||
syn match NixINT /\<[0-9]\+\>/
|
||||
syn match NixPATH /[a-zA-Z0-9\.\_\-\+]*\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/
|
||||
syn match NixHPATH /\~\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/
|
||||
syn match NixSPATH /<[a-zA-Z0-9\.\_\-\+]\+\(\/[a-zA-Z0-9\.\_\-\+]\+\)*>/
|
||||
syn match NixURI /[a-zA-Z][a-zA-Z0-9\+\-\.]*:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']\+/
|
||||
syn region NixSTRING
|
||||
\ matchgroup=NixSTRING
|
||||
\ start='"'
|
||||
\ skip='\\"'
|
||||
\ end='"'
|
||||
syn region NixIND_STRING
|
||||
\ matchgroup=NixIND_STRING
|
||||
\ start="'''"
|
||||
\ skip="'''\('\|[$]\|\\[nrt]\)"
|
||||
\ end="'''"
|
||||
|
||||
syn match NixOther /[-!+&<>|():/;=.,?\[\]*@]/
|
||||
|
||||
syn match NixCommentMatch /\(^\|\s\)#.*/
|
||||
syn region NixCommentRegion start="/\*" end="\*/"
|
||||
|
||||
hi link NixCode Statement
|
||||
hi link NixData Constant
|
||||
hi link NixComment Comment
|
||||
|
||||
hi link NixCommentMatch NixComment
|
||||
hi link NixCommentRegion NixComment
|
||||
hi link NixID NixCode
|
||||
hi link NixINT NixData
|
||||
hi link NixPATH NixData
|
||||
hi link NixHPATH NixData
|
||||
hi link NixSPATH NixData
|
||||
hi link NixURI NixData
|
||||
hi link NixSTRING NixData
|
||||
hi link NixIND_STRING NixData
|
||||
|
||||
hi link NixEnter NixCode
|
||||
hi link NixOther NixCode
|
||||
hi link NixQuote NixData
|
||||
|
||||
syn cluster nix_has_dollar_curly contains=@nix_ind_strings,@nix_strings
|
||||
syn cluster nix_ind_strings contains=NixIND_STRING
|
||||
syn cluster nix_strings contains=NixSTRING
|
||||
|
||||
${concatStringsSep "\n" (mapAttrsToList (name:
|
||||
{ extraStart ? null, lang ? name }:
|
||||
let
|
||||
startAlts = filter isString [ "/\\* ${name} \\*/" extraStart ];
|
||||
sigil = "\\(${concatStringsSep "\\|" startAlts}\\)[ \\t\\r\\n]*";
|
||||
# vim
|
||||
in ''
|
||||
syn include @nix_${lang}_syntax syntax/${lang}.vim
|
||||
if exists("b:current_syntax")
|
||||
unlet b:current_syntax
|
||||
endif
|
||||
|
||||
syn match nix_${lang}_sigil
|
||||
\ X${replaceStrings [ "X" ] [ "\\X" ] sigil}\ze\('''\|"\)X
|
||||
\ nextgroup=nix_${lang}_region_IND_STRING,nix_${lang}_region_STRING
|
||||
\ transparent
|
||||
|
||||
syn region nix_${lang}_region_STRING
|
||||
\ matchgroup=NixSTRING
|
||||
\ start='"'
|
||||
\ skip='\\"'
|
||||
\ end='"'
|
||||
\ contained
|
||||
\ contains=@nix_${lang}_syntax
|
||||
\ transparent
|
||||
|
||||
syn region nix_${lang}_region_IND_STRING
|
||||
\ matchgroup=NixIND_STRING
|
||||
\ start="'''"
|
||||
\ skip="'''\('\|[$]\|\\[nrt]\)"
|
||||
\ end="'''"
|
||||
\ contained
|
||||
\ contains=@nix_${lang}_syntax
|
||||
\ transparent
|
||||
|
||||
syn cluster nix_ind_strings
|
||||
\ add=nix_${lang}_region_IND_STRING
|
||||
|
||||
syn cluster nix_strings
|
||||
\ add=nix_${lang}_region_STRING
|
||||
|
||||
" This is required because containedin isn't transitive.
|
||||
syn cluster nix_has_dollar_curly
|
||||
\ add=@nix_${lang}_syntax
|
||||
'') {
|
||||
c = { };
|
||||
cabal = { };
|
||||
diff = { };
|
||||
haskell = { };
|
||||
python = { };
|
||||
lua = { };
|
||||
sed.extraStart = ''writeSed[^ \t\r\n]*[ \t\r\n]*"[^"]*"'';
|
||||
sh.extraStart = concatStringsSep "\\|" [
|
||||
''
|
||||
write\(A\|Ba\|Da\)sh[^ \t\r\n]*[ \t\r\n]*\("[^"]*"\|[a-z]\+\)''
|
||||
"[a-z]*Phase[ \\t\\r\\n]*="
|
||||
];
|
||||
yaml = { };
|
||||
vim.extraStart = ''
|
||||
write[^ \t\r\n]*[ \t\r\n]*"\(\([^"]*\.\)\?vimrc\|[^"]*\.vim\)"'';
|
||||
xdefaults = { };
|
||||
})}
|
||||
|
||||
" Clear syntax that interferes with nixINSIDE_DOLLAR_CURLY.
|
||||
syn clear shVarAssign
|
||||
|
||||
syn region nixINSIDE_DOLLAR_CURLY
|
||||
\ matchgroup=NixEnter
|
||||
\ start="[$]{"
|
||||
\ end="}"
|
||||
\ contains=TOP
|
||||
\ containedin=@nix_has_dollar_curly
|
||||
\ transparent
|
||||
|
||||
syn region nix_inside_curly
|
||||
\ matchgroup=NixEnter
|
||||
\ start="{"
|
||||
\ end="}"
|
||||
\ contains=TOP
|
||||
\ containedin=nixINSIDE_DOLLAR_CURLY,nix_inside_curly
|
||||
\ transparent
|
||||
|
||||
syn match NixQuote /'''\($\|\\.\)/he=s+2
|
||||
\ containedin=@nix_ind_strings
|
||||
\ contained
|
||||
|
||||
syn match NixQuote /'''\('\|\\.\)/he=s+1
|
||||
\ containedin=@nix_ind_strings
|
||||
\ contained
|
||||
|
||||
syn match NixQuote /\\./he=s+1
|
||||
\ containedin=@nix_strings
|
||||
\ contained
|
||||
|
||||
syn sync fromstart
|
||||
|
||||
let b:current_syntax = "nix"
|
||||
|
||||
set isk=@,48-57,_,192-255,-,'
|
||||
'';
|
||||
"/syntax/sed.vim".text = # vim
|
||||
''
|
||||
syn region sedBranch
|
||||
\ matchgroup=sedFunction start="T"
|
||||
\ matchgroup=sedSemicolon end=";\|$"
|
||||
\ contains=sedWhitespace
|
||||
'';
|
||||
}));
|
||||
|
||||
# active plugins
|
||||
# --------------
|
||||
extra-runtimepath = with pkgs;
|
||||
lib.concatMapStringsSep "," (pkg: "${pkg.rtp}") [
|
||||
vimPlugins.Syntastic
|
||||
vimPlugins.ack-vim
|
||||
vimPlugins.airline
|
||||
vimPlugins.vim-nix
|
||||
vimPlugins.xptemplate
|
||||
vim-tv-plugin
|
||||
];
|
||||
|
||||
# the vimrc
|
||||
# ---------
|
||||
vimrc = pkgs.writeText "vimrc" ''
|
||||
|
||||
" turn on linenumbers
|
||||
" to turn of :set nonumber
|
||||
:set number
|
||||
|
||||
" show Trailing Whitespaces
|
||||
:set list listchars=tab:»·,trail:¶
|
||||
|
||||
" Map leader is the key for shortcuts
|
||||
nnoremap <SPACE> <Nop>
|
||||
let mapleader = "\<Space>"
|
||||
|
||||
" move blocks of text in visual mode
|
||||
" does not work correctly
|
||||
vmap <up> xkP`[V`]
|
||||
vmap <down> xp`[V`]
|
||||
|
||||
" search/grep case insensitive
|
||||
:set ignorecase
|
||||
|
||||
" tabs should always be 2 spaces
|
||||
set et ts=2 sts=2 sw=2
|
||||
|
||||
" installed vim-plugins
|
||||
set runtimepath=${extra-runtimepath},$VIMRUNTIME,$HOME/.vim,${nix-xptemplates}
|
||||
|
||||
" syntax highlighting on
|
||||
syntax on
|
||||
|
||||
" xptemplates
|
||||
" -----------
|
||||
" a plugin to insert snippets on demand
|
||||
set nocompatible
|
||||
filetype plugin on
|
||||
|
||||
" enable cursor cross
|
||||
" -------------------
|
||||
":hi CursorLine cterm=NONE ctermbg=darkred ctermfg=white guibg=darkred guifg=white
|
||||
":hi CursorColumn cterm=NONE ctermbg=darkred ctermfg=white guibg=darkred guifg=white
|
||||
:hi CursorLine cterm=NONE ctermbg=0 guibg=#073642
|
||||
:hi CursorColumn cterm=NONE ctermbg=0 guibg=#073642
|
||||
set cursorline
|
||||
set cursorcolumn
|
||||
|
||||
" save view
|
||||
" ---------
|
||||
augroup AutoSaveFolds
|
||||
autocmd!
|
||||
autocmd BufWinLeave * mkview
|
||||
autocmd BufWinEnter * silent loadview
|
||||
augroup END
|
||||
|
||||
" some language stuff
|
||||
" -------------------
|
||||
:map <leader>s :setlocal spell spelllang=en
|
||||
|
||||
'';
|
||||
|
||||
in {
|
||||
|
||||
# no options
|
||||
options.programs.custom.vim.enable = lib.mkEnableOption "vim";
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# create vimrc
|
||||
# ------------
|
||||
# and load it as config for vim
|
||||
environment.variables.VIMINIT = ":so /etc/vimrc";
|
||||
environment.etc.vimrc.source = vimrc;
|
||||
|
||||
# set vim to the default editor
|
||||
# -----------------------------
|
||||
programs.vim.defaultEditor = true;
|
||||
|
||||
# install vim
|
||||
# -----------
|
||||
environment.systemPackages = [ pkgs.vim ];
|
||||
};
|
||||
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.system.permown;
|
||||
nameGenerator = path: "permown.${replaceStrings [ "/" ] [ "_" ] path}";
|
||||
|
||||
in {
|
||||
|
||||
options.system.permown = mkOption {
|
||||
default = { };
|
||||
type = with types;
|
||||
attrsOf (submodule ({ config, ... }: {
|
||||
options = {
|
||||
directory-mode = mkOption {
|
||||
default = "=rwx";
|
||||
type = types.str;
|
||||
};
|
||||
file-mode = mkOption {
|
||||
default = "=rw";
|
||||
type = types.str;
|
||||
};
|
||||
group = mkOption {
|
||||
apply = x: if x == null then "" else x;
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
};
|
||||
owner = mkOption { type = types.str; };
|
||||
path = mkOption {
|
||||
default = config._module.args.name;
|
||||
type = types.path;
|
||||
};
|
||||
umask = mkOption {
|
||||
default = "0027";
|
||||
type = types.str;
|
||||
};
|
||||
timer = mkOption {
|
||||
default = "hourly";
|
||||
type = types.str;
|
||||
description =
|
||||
"OnCalendar string on how frequent should this command run";
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
config = let plans = lib.attrValues cfg;
|
||||
|
||||
in mkIf (plans != [ ]) {
|
||||
|
||||
system.activationScripts.permown = let
|
||||
mkdir = { path, ... }: ''
|
||||
${pkgs.coreutils}/bin/mkdir -p ${path}
|
||||
'';
|
||||
in concatMapStrings mkdir plans;
|
||||
|
||||
systemd.services = listToAttrs (flip map plans
|
||||
({ path, directory-mode, file-mode, owner, group, umask, ... }: {
|
||||
name = nameGenerator path;
|
||||
value = {
|
||||
environment = {
|
||||
DIR_MODE = directory-mode;
|
||||
FILE_MODE = file-mode;
|
||||
OWNER_GROUP = "${owner}:${group}";
|
||||
ROOT_PATH = path;
|
||||
};
|
||||
path = [ pkgs.coreutils pkgs.findutils pkgs.inotifyTools ];
|
||||
serviceConfig = {
|
||||
ExecStart = pkgs.writers.writeDash "permown" ''
|
||||
set -efu
|
||||
find "$ROOT_PATH" -exec chown -h "$OWNER_GROUP" {} +
|
||||
find "$ROOT_PATH" -type d -exec chmod "$DIR_MODE" {} +
|
||||
find "$ROOT_PATH" -type f -exec chmod "$FILE_MODE" {} +
|
||||
'';
|
||||
PrivateTmp = true;
|
||||
Restart = "always";
|
||||
RestartSec = 10;
|
||||
UMask = umask;
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
}));
|
||||
|
||||
systemd.timers = listToAttrs (flip map plans ({ path, timer, ... }: {
|
||||
name = nameGenerator path;
|
||||
value = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
timerConfig.OnCalendar = timer;
|
||||
};
|
||||
}));
|
||||
|
||||
};
|
||||
|
||||
}
|
1
nixos/assets/ssh/borg_access.pub
Normal file
1
nixos/assets/ssh/borg_access.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC/WCoJ9zSL85R1mNJHUGRofyigeg2+g4+bwWVysHxWroPMIpP2hJrMRPoP13SAOaLOjl6X112jjoQ2wpJ/qptjtojrsF8bpFgoMqCQFsQDD4zuG4V/AaIt0nAF4B5tDBGFN3Hj6vpbwVAidv+8Kr41r5JOG/8Z/UiJDGrIMab3kDwyOklrMPLWr7IBYC0O8Jwyz3lAl18ukMSEZvoPaJhPJyyqRhSagX59U7AQiNrnq18kzi7Pszy3e1d7x3vWSXemJGZaUJ+cFbl1LrvFHwUa55sSUVUVBRxgABc906YoiUcr31aw98zUX4W+2+AqDzIIquV5frIc/+nnfsmDrsnMl81cLglxuRxqib0AuSYqkNQimWrR61M7TaLvGZomMk8Vheew/QlxvHvhbHwnu7/tgNll2i+Zi1T7VZ5Hcy4quYDZQA7NDrvu0dEm+dTlOfuJJZdMLWws20ao8xtv8IxxCN31CBCbCSETpsSuvT7joHKGpJoOf3eilLLqOKjrbo5E6s6S1w1WRoZ6LuXQo2l5uvMVSzUZ+4CG+FX+Q73bpQ5SWUvz2o5HovX8RbcneuG7mfZMe80F5IyaqSmi0r+kFOqK4NKz/InHhSJjrFYJWl2PP+30MfsHx5NMOVhfKdRZje5oTds6L2o9+3vhiE7CmgZVR+RqMHMUtRrERODwPQ==
|
1
nixos/assets/ssh/jenkins.pub
Normal file
1
nixos/assets/ssh/jenkins.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDIZ8ezpjX1nI/Im+krulJNaVd1DZeFvcgX3x197DIbBgCsBjAW8WuV2tzmcrWSjWJ6lfmLlzplOLzhTNG763sbNQ5amfhglYTmQhruGcSXNkdsjOyoxK8SX3wH6Kv/Q0CpoyAYOB9fiJnUyWB9BXSI8VYMMRFj6+cPiZc6NhnnlxU+6uH3VvzV5hsAaT4mpXJJEidMqE9DpGFguOekOUO7HCVcZeQQjazl1u+NhbqRI3CsJjXBqiqAFSMzKOXhTk36xd2WLEmCaPnWuWf7imvR+T3JVPFTNGec3wMbT5nnMiK0/hbowyDQCbtnUVWja9ftVsOH55tLRSY16GnXngUzw+trxWOvX0wOFOhfSZ2k1WtjTlNtOEhne/V0a3bocel/7JuXBX3RvWAEVl1sWS5R9MG8aDB8S2fx8qZirbg0NZticAxcHtg0RyJRzH6DYrkINE6cUgK7qsrUtaY1W6Qj6Jp33Li8KHY2JElDvJLhAx8v7l6BaZkog/Z0raR8RSRefiDQZJ8qiqPXUJG1pQm4Mp8IGL5PAmi0AZg6QL2pkXC0pyg1xE4TdRjOeuV/vdVDX15xCsgOJjK7PGNoNm2JpYA8vaWMHG8Ujk4UBHolooKeuL3g0CcgzfyRMp/Dxlk1BhgRQ17VxWBDuKt3bWuTJIvmrvDuPB3vd+WYNNqskQ==
|
|
@ -7,8 +7,8 @@
|
|||
allowSubRepos = true;
|
||||
authorizedKeys = [
|
||||
# todo rename
|
||||
(lib.fileContents <common_secrets/backup/ssh_rsa.pub>)
|
||||
(lib.fileContents <assets/ssh/card_rsa.pub>)
|
||||
(lib.fileContents ../../assets/ssh/borg_access.pub)
|
||||
(lib.fileContents ../../assets/ssh/card_rsa.pub)
|
||||
];
|
||||
};
|
||||
};
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
imports = [
|
||||
|
||||
<system/server>
|
||||
../../system/server
|
||||
./hardware-configuration.nix
|
||||
|
||||
#./home-assistant.nix
|
||||
|
@ -13,10 +13,14 @@
|
|||
#./lan.nix
|
||||
./dms.nix
|
||||
./borg.nix
|
||||
./mpd.nix
|
||||
./grocy.nix
|
||||
./taskwarrior-pushover.nix
|
||||
|
||||
];
|
||||
|
||||
nixpkgs.config.permittedInsecurePackages = [ "homeassistant-0.114.4" ];
|
||||
sops.defaultSopsFile = ../../secrets/pepe.yaml;
|
||||
|
||||
|
||||
networking.hostName = "pepe";
|
||||
|
|
@ -11,7 +11,8 @@ let
|
|||
rev = "2f5c44f017bdfd8abfe908d419ef26bac300f809";
|
||||
sha256 = "0dxhk1ah6wwbsxyk4hd32rz7886w7r5gfy16485gjbvky1qsi8gd";
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
# setup ftp
|
||||
services.vsftpd = {
|
||||
|
@ -39,9 +40,11 @@ in {
|
|||
}
|
||||
];
|
||||
|
||||
sops.secrets.ftp_password = { };
|
||||
|
||||
# create user
|
||||
users.users.ftp-upload = {
|
||||
passwordFile = toString <secrets/ftp/password>;
|
||||
passwordFile = config.sops.secrets.ftp_password.path;
|
||||
isNormalUser = true;
|
||||
};
|
||||
|
16
nixos/configs/pepe/grocy.nix
Normal file
16
nixos/configs/pepe/grocy.nix
Normal file
|
@ -0,0 +1,16 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.grocy = {
|
||||
enable = true;
|
||||
settings = {
|
||||
culture = "de";
|
||||
currency = "EUR";
|
||||
};
|
||||
hostName = "grocy.pepe.private";
|
||||
nginx.enableSSL = false;
|
||||
};
|
||||
|
||||
backup.dirs = [ config.services.grocy.dataDir ];
|
||||
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ modulesPath, config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
<nixpkgs/nixos/modules/installer/scan/not-detected.nix>
|
||||
"${modulesPath}/installer/scan/not-detected.nix"
|
||||
|
||||
(let mediaUUID = "29ebe5ba-7599-4dd3-99a3-37b9bf8e4d61";
|
||||
(
|
||||
let mediaUUID = "29ebe5ba-7599-4dd3-99a3-37b9bf8e4d61";
|
||||
in {
|
||||
fileSystems."/media" = {
|
||||
device = "/dev/disk/by-uuid/${mediaUUID}";
|
||||
|
@ -26,7 +27,8 @@
|
|||
what = "/dev/disk/by-uuid/${mediaUUID}";
|
||||
where = "/media";
|
||||
}];
|
||||
})
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules =
|
|
@ -1,6 +1,4 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
let unstablePkgs = import <nixpkgs-unstable> { };
|
||||
in {
|
||||
{ pkgs, config, lib, ... }: {
|
||||
|
||||
imports = [
|
||||
#./home-assistant/mpd.nix
|
||||
|
@ -156,7 +154,8 @@ in {
|
|||
|
||||
{
|
||||
alias = "reset everything when back home";
|
||||
trigger = map (entity_id: {
|
||||
trigger = map
|
||||
(entity_id: {
|
||||
platform = "state";
|
||||
entity_id = entity_id;
|
||||
from = "off";
|
||||
|
@ -187,7 +186,8 @@ in {
|
|||
|
||||
];
|
||||
|
||||
group = let
|
||||
group =
|
||||
let
|
||||
create_room = { name, description }: {
|
||||
"${name}" = {
|
||||
name = "${description}";
|
||||
|
@ -198,7 +198,8 @@ in {
|
|||
lib.foldr (a: b: a // b) { } (map create_room rooms);
|
||||
# rooms
|
||||
# -----
|
||||
in (create_rooms [
|
||||
in
|
||||
(create_rooms [
|
||||
{
|
||||
name = "floor_room";
|
||||
description = "Flur";
|
||||
|
@ -243,9 +244,9 @@ in {
|
|||
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
package = unstablePkgs.home-assistant;
|
||||
#package = unstablePkgs.home-assistant.override {
|
||||
# python3 = unstablePkgs.python37;
|
||||
package = pkgs.unstable.home-assistant;
|
||||
#package = pkgs.unstable.home-assistant.override {
|
||||
# python3 = pkgs.unstable.python37;
|
||||
# extraPackages = python: [
|
||||
# # todo : check which is still needed
|
||||
# python.netdisco
|
|
@ -5,7 +5,8 @@ let
|
|||
folderPath = config.services.home-assistant.configDir;
|
||||
filePath = "${folderPath}/${name}.json";
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
sensor = [
|
232
nixos/configs/pepe/home-assistant/light-control.nix
Normal file
232
nixos/configs/pepe/home-assistant/light-control.nix
Normal file
|
@ -0,0 +1,232 @@
|
|||
{ pkgs, lib, config, ... }: {
|
||||
|
||||
services.mqtt.light-control.enable = true;
|
||||
services.mqtt.light-control.loglevel = "debug";
|
||||
services.mqtt.light-control.config = {
|
||||
credentials = {
|
||||
host = "tcp://localhost:1883";
|
||||
user = "homeassistant";
|
||||
password = "hallo";
|
||||
};
|
||||
scenes = [
|
||||
{
|
||||
name = "up-dark";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "half";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
disabled_switches = [
|
||||
"zigbee2mqtt/led_1"
|
||||
"zigbee2mqtt/led_2"
|
||||
"zigbee2mqtt/light_2"
|
||||
"zigbee2mqtt/light_4"
|
||||
"zigbee2mqtt/light_5"
|
||||
"zigbee2mqtt/light_7"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "down";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "up-bright";
|
||||
disabled_switches = [
|
||||
"zigbee2mqtt/led_1"
|
||||
"zigbee2mqtt/led_2"
|
||||
"zigbee2mqtt/light_2"
|
||||
"zigbee2mqtt/light_4"
|
||||
"zigbee2mqtt/light_5"
|
||||
"zigbee2mqtt/light_7"
|
||||
];
|
||||
ignored_sensors = [ "zigbee2mqtt/door_sensor_4" ];
|
||||
}
|
||||
{
|
||||
name = "outside";
|
||||
room_tracking_enabled = false;
|
||||
ignored_sensors = [ "zigbee2mqtt/door_sensor_4" ];
|
||||
}
|
||||
{
|
||||
name = "night";
|
||||
room_tracking_enabled = false;
|
||||
brightness = 25;
|
||||
ignored_sensors =
|
||||
[ "zigbee2mqtt/motion_sensor_7" "zigbee2mqtt/door_sensor_4" ];
|
||||
}
|
||||
];
|
||||
sensors =
|
||||
let
|
||||
door = { topic, room }: {
|
||||
topic = topic;
|
||||
key = "contact";
|
||||
room = room;
|
||||
invert_state = true;
|
||||
delay = 90;
|
||||
};
|
||||
motion = { topic, room }: {
|
||||
topic = topic;
|
||||
key = "occupancy";
|
||||
room = room;
|
||||
delay = 60;
|
||||
};
|
||||
in
|
||||
[
|
||||
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_1";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_2";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_6";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_8";
|
||||
room = "office_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_7";
|
||||
room = "sleeping_room";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_5";
|
||||
room = "kitchen";
|
||||
})
|
||||
(motion {
|
||||
topic = "zigbee2mqtt/motion_sensor_4";
|
||||
room = "storage_room";
|
||||
})
|
||||
|
||||
(door {
|
||||
topic = "zigbee2mqtt/door_sensor_1";
|
||||
room = "storage_room";
|
||||
})
|
||||
(door {
|
||||
topic = "zigbee2mqtt/door_sensor_5";
|
||||
room = "sleeping_room";
|
||||
})
|
||||
(door {
|
||||
# house door
|
||||
topic = "zigbee2mqtt/door_sensor_4";
|
||||
room = "floor";
|
||||
})
|
||||
|
||||
];
|
||||
switches =
|
||||
let
|
||||
sonoff = { id, rooms, delay ? 0 }: {
|
||||
topic = "stat/${id}/RESULT";
|
||||
key = "POWER";
|
||||
rooms = rooms;
|
||||
delay = delay;
|
||||
command = {
|
||||
command = "{{state}}";
|
||||
init_command = "(null)";
|
||||
topic = "cmnd/${id}/POWER";
|
||||
on = "ON";
|
||||
off = "OFF";
|
||||
};
|
||||
};
|
||||
light = { topic, rooms, delay ? 0 }: {
|
||||
topic = topic;
|
||||
key = "state";
|
||||
rooms = rooms;
|
||||
delay = delay;
|
||||
command = {
|
||||
command = ''{"state":"{{state}}","brightness":{{brightness}}}'';
|
||||
topic = "${topic}/set";
|
||||
on = "ON";
|
||||
off = "OFF";
|
||||
};
|
||||
};
|
||||
led = { topic, rooms, delay ? 0 }: {
|
||||
topic = topic;
|
||||
key = "state";
|
||||
rooms = rooms;
|
||||
delay = delay;
|
||||
command = {
|
||||
# Configure it once to the color you like
|
||||
# {"state":"{{state}}","brightness":{{brightness}},"color":{"hex":"#FFFFFF},"color_temp":255","transition":0}
|
||||
command = ''
|
||||
{"state":"{{state}}","brightness":{{brightness}},"transition":0}'';
|
||||
topic = "${topic}/set";
|
||||
on = "ON";
|
||||
off = "OFF";
|
||||
};
|
||||
};
|
||||
in
|
||||
[
|
||||
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_2";
|
||||
rooms = [ "office_room" ];
|
||||
})
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_4";
|
||||
rooms = [ "office_room" ];
|
||||
})
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_5";
|
||||
rooms = [ "storage_room" ];
|
||||
})
|
||||
(light {
|
||||
topic = "zigbee2mqtt/light_7";
|
||||
rooms = [ "sleeping_room" ];
|
||||
})
|
||||
(led {
|
||||
topic = "zigbee2mqtt/led_1";
|
||||
rooms = [ "office_room" ];
|
||||
})
|
||||
(led {
|
||||
topic = "zigbee2mqtt/led_2";
|
||||
rooms = [ "kitchen" ];
|
||||
})
|
||||
|
||||
#(sonoff {
|
||||
# id = "PAL01";
|
||||
# rooms = [ "bed_room" ];
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL03";
|
||||
# rooms = [ "living_room" ];
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL04";
|
||||
# rooms = [ "bed_room" ];
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL06";
|
||||
# rooms = [ "kitchen" ];
|
||||
#})
|
||||
## monitor and speakers
|
||||
#(sonoff {
|
||||
# id = "PAL07";
|
||||
# rooms = [ "bed_room" ];
|
||||
# delay = 180;
|
||||
#})
|
||||
#(sonoff {
|
||||
# id = "PAL08";
|
||||
# rooms = [ "bed_room" ];
|
||||
# delay = 180;
|
||||
#})
|
||||
|
||||
];
|
||||
};
|
||||
|
||||
}
|
|
@ -39,7 +39,8 @@ let
|
|||
|
||||
toSwitch = name: "switch.${name}";
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
imports = [ ./mqtt.nix ];
|
||||
|
||||
|
@ -47,18 +48,21 @@ in {
|
|||
|
||||
# nicer names
|
||||
# -----------
|
||||
homeassistant.customize = lib.mapAttrs' (entity:
|
||||
homeassistant.customize = lib.mapAttrs'
|
||||
(entity:
|
||||
{ label, icon ? "mdi:power-plug-off", ... }: {
|
||||
name = toSwitch entity;
|
||||
value = {
|
||||
friendly_name = label;
|
||||
icon = icon;
|
||||
};
|
||||
}) sonoffSwitches;
|
||||
})
|
||||
sonoffSwitches;
|
||||
|
||||
# define switches
|
||||
# ---------------
|
||||
switch = lib.mapAttrsToList (name:
|
||||
switch = lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: {
|
||||
name = name;
|
||||
platform = "mqtt";
|
||||
|
@ -68,7 +72,8 @@ in {
|
|||
payload_off = "OFF";
|
||||
state_on = "ON";
|
||||
state_off = "OFF";
|
||||
}) sonoffSwitches;
|
||||
})
|
||||
sonoffSwitches;
|
||||
|
||||
# discover state on init
|
||||
# ----------------------
|
||||
|
@ -78,27 +83,34 @@ in {
|
|||
platform = "homeassistant";
|
||||
event = "start";
|
||||
};
|
||||
action = lib.mapAttrsToList (name:
|
||||
action = lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: {
|
||||
service = "mqtt.publish";
|
||||
data = {
|
||||
topic = "cmnd/${lib.toUpper name}/power";
|
||||
payload = "";
|
||||
};
|
||||
}) sonoffSwitches;
|
||||
})
|
||||
sonoffSwitches;
|
||||
}];
|
||||
|
||||
# append to groups
|
||||
# ----------------
|
||||
group = let
|
||||
group =
|
||||
let
|
||||
# sort lights into given groups.
|
||||
sortedInGroups = let
|
||||
groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList (name:
|
||||
sortedInGroups =
|
||||
let
|
||||
groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ groups ? [ ], ... }:
|
||||
map (groupName: { "${groupName}" = "switch.${name}"; }) groups)
|
||||
sonoffSwitches));
|
||||
in lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
in sortedInGroups;
|
||||
in
|
||||
lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
in
|
||||
sortedInGroups;
|
||||
};
|
||||
|
||||
}
|
182
nixos/configs/pepe/home-assistant/stocks.nix
Normal file
182
nixos/configs/pepe/home-assistant/stocks.nix
Normal file
|
@ -0,0 +1,182 @@
|
|||
{ lib, config, pkgs, ... }:
|
||||
let
|
||||
|
||||
folderPath = config.services.home-assistant.configDir;
|
||||
|
||||
# find symbols with
|
||||
# https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords=<keywords>&apikey=<api_key>
|
||||
# as described here : https://www.alphavantage.co/documentation/#symbolsearch
|
||||
#
|
||||
# example:
|
||||
# --------
|
||||
# stocks = [
|
||||
# {
|
||||
# symbol = "GOOGL";
|
||||
# name = "google";
|
||||
# friendly_name = "Google";
|
||||
# currency = "$";
|
||||
# # I own 50 and bought at a price of 1000
|
||||
# own = {
|
||||
# pieces = 50;
|
||||
# price = 1000;
|
||||
# };
|
||||
# }
|
||||
# ];
|
||||
stocks = import <secrets/home-assistant/stocks>;
|
||||
filePath = name: "${folderPath}/stock_${name}.json";
|
||||
|
||||
cleanup_list = list: lib.filter (entry: entry != { }) (lib.flatten list);
|
||||
|
||||
in
|
||||
{
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
sensor = cleanup_list (map
|
||||
({ name, currency, own ? { }, ... }: [
|
||||
{
|
||||
platform = "file";
|
||||
name = "stock_${name}";
|
||||
file_path = filePath name;
|
||||
value_template = "{{ value_json.price}} ${currency}";
|
||||
|
||||
}
|
||||
{
|
||||
platform = "file";
|
||||
name = "stock_${name}_change";
|
||||
file_path = filePath name;
|
||||
value_template = "{{ value_json.change}} ${currency}";
|
||||
|
||||
}
|
||||
{
|
||||
platform = "file";
|
||||
name = "stock_${name}_change_percent";
|
||||
file_path = filePath name;
|
||||
value_template = "{{ value_json.change_percent}} %";
|
||||
}
|
||||
(lib.optionalAttrs (own != { }) {
|
||||
platform = "file";
|
||||
name = "stock_${name}_profit";
|
||||
file_path = filePath name;
|
||||
value_template = ''
|
||||
{{ "{:,.2f}".format( value_json.price * ${toString own.pieces} - ${
|
||||
toString (own.pieces * own.price)
|
||||
} ) }} ${currency}'';
|
||||
})
|
||||
])
|
||||
stocks);
|
||||
|
||||
homeassistant = {
|
||||
whitelist_external_dirs = [ folderPath ];
|
||||
customize = builtins.listToAttrs (cleanup_list (map
|
||||
({ name, own ? { }, ... }: [
|
||||
{
|
||||
name = "sensor.stock_${name}";
|
||||
value = {
|
||||
icon = "mdi:cash-usd-outline";
|
||||
friendly_name = "Price";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "sensor.stock_${name}_change";
|
||||
value = {
|
||||
icon = "mdi:radar";
|
||||
friendly_name = "Difference";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "sensor.stock_${name}_change_percent";
|
||||
value = {
|
||||
icon = "mdi:radar";
|
||||
friendly_name = "Percent";
|
||||
};
|
||||
}
|
||||
(lib.optionalAttrs (own != { }) {
|
||||
name = "sensor.stock_${name}_profit";
|
||||
value = {
|
||||
icon = "mdi:radar";
|
||||
friendly_name = "Profit";
|
||||
};
|
||||
})
|
||||
])
|
||||
stocks));
|
||||
};
|
||||
|
||||
group = (builtins.listToAttrs (map
|
||||
({ name, friendly_name, own ? { }, ... }: {
|
||||
name = "stock_${name}";
|
||||
value = {
|
||||
name = "${friendly_name} Aktie";
|
||||
entities = [
|
||||
"sensor.stock_${name}"
|
||||
"sensor.stock_${name}_change"
|
||||
"sensor.stock_${name}_change_percent"
|
||||
] ++ (lib.optional (own != { }) "sensor.stock_${name}_profit");
|
||||
};
|
||||
})
|
||||
stocks));
|
||||
|
||||
};
|
||||
|
||||
systemd.services =
|
||||
let
|
||||
pullService = { name, symbol, currency, ... }: {
|
||||
name = "pull_stock_${name}";
|
||||
value = {
|
||||
enable = true;
|
||||
before = [ "home-assistant.service" ];
|
||||
wantedBy = [ "home-assistant.service" ];
|
||||
serviceConfig = {
|
||||
User = "hass";
|
||||
Type = "oneshot";
|
||||
};
|
||||
description = "pull stock_${name} for homeassistant";
|
||||
script = ''
|
||||
SYMBOL="${symbol}"
|
||||
CURRENCY="${currency}"
|
||||
APIKEY=${
|
||||
lib.fileContents <secrets/home-assistant/alphavantage/apikey>
|
||||
}
|
||||
|
||||
${pkgs.curl}/bin/curl --location --silent \
|
||||
"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=$SYMBOL&apikey=$APIKEY" \
|
||||
| ${pkgs.jq}/bin/jq --compact-output \
|
||||
'.["Global Quote"] |
|
||||
{
|
||||
price: .["05. price"] | tonumber,
|
||||
currency: "'$CURRENCY'",
|
||||
change_percent: .["10. change percent"] | .[0:-1] | tonumber,
|
||||
change: .["09. change"] | tonumber,
|
||||
last_date: .["07. latest trading day"],
|
||||
}' \
|
||||
>> ${filePath name}
|
||||
|
||||
# old and stupid
|
||||
#${pkgs.curl}/bin/curl --location --silent \
|
||||
#"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=$SYMBOL&interval=5min&apikey=$APIKEY" \
|
||||
#| ${pkgs.jq}/bin/jq --compact-output \
|
||||
# '.["Time Series (5min)"] | to_entries | [ .[]
|
||||
# | { date : .key , value : .value["4. close"], currency: "'$CURRENCY'" } ]
|
||||
# | sort_by(.date) | reverse | .[0]' \
|
||||
'';
|
||||
};
|
||||
};
|
||||
in
|
||||
builtins.listToAttrs (map pullService stocks);
|
||||
|
||||
systemd.timers =
|
||||
let
|
||||
pullTimer = { name, ... }: {
|
||||
name = "pull_stock_${name}";
|
||||
value = {
|
||||
enable = true;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "hourly";
|
||||
Persistent = "true";
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
builtins.listToAttrs (map pullTimer stocks);
|
||||
|
||||
}
|
|
@ -11,7 +11,8 @@ let
|
|||
#];
|
||||
holidays = lib.flatten (privateHolidays holiday-range);
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
binary_sensor = [
|
|
@ -2,8 +2,7 @@
|
|||
# no need to set ZIGBEE2MQTT_DATA anymore
|
||||
assert lib.versionOlder lib.version "21.03";
|
||||
|
||||
let unstable = import <nixpkgs-unstable> { };
|
||||
in {
|
||||
{
|
||||
imports = [
|
||||
./mqtt.nix
|
||||
./zigbee2mqtt/service.nix
|
||||
|
@ -23,7 +22,7 @@ in {
|
|||
enable = true;
|
||||
#package = pkgs.own_zigbee2mqtt;
|
||||
#package = unstable.zigbee2mqtt;
|
||||
package = unstable.zigbee2mqtt.overrideAttrs (old: rec {
|
||||
package = pkgs.unstable.zigbee2mqtt.overrideAttrs (old: rec {
|
||||
version = "1.18.1";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "Koenkk";
|
250
nixos/configs/pepe/home-assistant/zigbee2mqtt/buttons.nix
Normal file
250
nixos/configs/pepe/home-assistant/zigbee2mqtt/buttons.nix
Normal file
|
@ -0,0 +1,250 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# we create 3 input_boolean which get toggled by the 3 types of buttons pressed.
|
||||
# input_boolean.single_${name} : single click
|
||||
# input_boolean.double_${name} : double click
|
||||
# input_boolean.hold_${name} : hold
|
||||
# if you override these input (via states) you have to create the input yourself
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/WXKG12LM.html
|
||||
allDevices = {
|
||||
"button_a1" = {
|
||||
id = "0x00158d0002b04f65";
|
||||
#groups = [ "living_room" ];
|
||||
states.single = "input_boolean.situation_toggle";
|
||||
states.hold = "input_boolean.printer_toggle";
|
||||
states.double = "input_boolean.windows_up";
|
||||
};
|
||||
"button_a2" = {
|
||||
id = "0x00158d0002b04f09";
|
||||
#groups = [ "bed_room" ];
|
||||
states.single = "input_boolean.situation_toggle";
|
||||
states.hold = "input_boolean.printer_toggle";
|
||||
states.double = "input_boolean.windows_up";
|
||||
};
|
||||
"button_a3" = {
|
||||
id = "0x00158d0002b00e04";
|
||||
#groups = [ "bed_room" ];
|
||||
states.single = "input_boolean.situation_toggle";
|
||||
states.hold = "input_boolean.printer_toggle";
|
||||
states.double = "input_boolean.windows_up";
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define input_boolean
|
||||
# --------------------
|
||||
# which get toggled by the buttons
|
||||
input_boolean =
|
||||
let stripEmpty = lib.filter (a: a != { });
|
||||
in builtins.listToAttrs (stripEmpty (lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ states ? { }, ... }: [
|
||||
(lib.optionalAttrs (!lib.hasAttr "single" states) {
|
||||
name = "single_${name}";
|
||||
value = { icon = "mdi:toggle-switch"; };
|
||||
})
|
||||
(lib.optionalAttrs (!lib.hasAttr "double" states) {
|
||||
name = "double_${name}";
|
||||
value = { icon = "mdi:toggle-switch"; };
|
||||
})
|
||||
(lib.optionalAttrs (!lib.hasAttr "hold" states) {
|
||||
name = "hold_${name}";
|
||||
value = { icon = "mdi:toggle-switch"; };
|
||||
})
|
||||
])
|
||||
allDevices)));
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: [
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = name;
|
||||
icon = "mdi:toggle-switch";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
value_template = "{{ value_json.click }}";
|
||||
}
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
])
|
||||
allDevices);
|
||||
|
||||
binary_sensor = lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: {
|
||||
name = name;
|
||||
platform = "mqtt";
|
||||
device_class = "motion";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
payload_on = true;
|
||||
payload_off = false;
|
||||
value_template = "{{ value_json.occupancy }}";
|
||||
})
|
||||
allDevices;
|
||||
|
||||
# create groups
|
||||
# -------------
|
||||
#group = let
|
||||
# # to have nice panels for every device
|
||||
# sensorGroups = lib.mapAttrs (name:
|
||||
# { states ? { }, ... }:
|
||||
# let
|
||||
# entityIds = { single ? "input_boolean.single_${name}"
|
||||
# , double ? "input_boolean.double_${name}"
|
||||
# , hold ? "input_boolean.hold_${name}", ... }: [
|
||||
# single
|
||||
# double
|
||||
# hold
|
||||
# ];
|
||||
# in {
|
||||
# entities = [ "sensor.${name}" ] ++ (entityIds states)
|
||||
# ++ [ "sensor.battery_${name}" "sensor.link_${name}" ];
|
||||
# }) allDevices;
|
||||
# # sort lights into given groups.
|
||||
# sortedInGroups = let
|
||||
# groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList (name:
|
||||
# { groups ? [ ], states ? { }, ... }:
|
||||
# map (groupName: {
|
||||
# "${groupName}" = if (lib.hasAttr "single" states) then
|
||||
# states.single
|
||||
# else
|
||||
# "input_boolean.single_${name}";
|
||||
# }) groups) allDevices));
|
||||
# in lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
#in sortedInGroups // sensorGroups // {
|
||||
# all_sensors.entities =
|
||||
# lib.mapAttrsToList (name: { ... }: "binary_sensor.${name}") allDevices;
|
||||
#};
|
||||
|
||||
# create automation
|
||||
# -----------------
|
||||
automation =
|
||||
let
|
||||
|
||||
# single click
|
||||
toggle_single_button_input = lib.mapAttrsToList
|
||||
(name:
|
||||
{ states ? { }, ... }:
|
||||
let
|
||||
entityId =
|
||||
if (lib.hasAttr "single" states) then
|
||||
states.single
|
||||
else
|
||||
"input_boolean.single_${name}";
|
||||
in
|
||||
{
|
||||
alias = "toggle single click ${name}";
|
||||
trigger = {
|
||||
platform = "mqtt";
|
||||
topic = "zigbee2mqtt/${name}";
|
||||
};
|
||||
condition = {
|
||||
condition = "template";
|
||||
value_template = ''{{ "single" == trigger.payload_json.click}}'';
|
||||
};
|
||||
action = {
|
||||
service = "input_boolean.toggle";
|
||||
data.entity_id = entityId;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
# double click
|
||||
toggle_double_button_input = lib.mapAttrsToList
|
||||
(name:
|
||||
{ states ? { }, ... }:
|
||||
let
|
||||
entityId =
|
||||
if (lib.hasAttr "double" states) then
|
||||
states.double
|
||||
else
|
||||
"input_boolean.double_${name}";
|
||||
in
|
||||
{
|
||||
alias = "toggle double click ${name}";
|
||||
trigger = {
|
||||
platform = "mqtt";
|
||||
topic = "zigbee2mqtt/${name}";
|
||||
};
|
||||
condition = {
|
||||
condition = "template";
|
||||
value_template = ''{{ "double" == trigger.payload_json.click}}'';
|
||||
};
|
||||
action = {
|
||||
service = "input_boolean.toggle";
|
||||
data.entity_id = entityId;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
# hold
|
||||
toggle_hold_button_input = lib.mapAttrsToList
|
||||
(name:
|
||||
{ states ? { }, ... }:
|
||||
let
|
||||
entityId =
|
||||
if (lib.hasAttr "hold" states) then
|
||||
states.hold
|
||||
else
|
||||
"input_boolean.hold_${name}";
|
||||
in
|
||||
{
|
||||
alias = "toggle hold ${name}";
|
||||
trigger = {
|
||||
platform = "mqtt";
|
||||
topic = "zigbee2mqtt/${name}";
|
||||
};
|
||||
condition = {
|
||||
condition = "template";
|
||||
value_template = ''{{ "hold" == trigger.payload_json.action}}'';
|
||||
};
|
||||
action = {
|
||||
service = "input_boolean.toggle";
|
||||
data.entity_id = entityId;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
in
|
||||
lib.flatten (toggle_single_button_input ++ toggle_double_button_input
|
||||
++ toggle_hold_button_input);
|
||||
|
||||
};
|
||||
|
||||
}
|
101
nixos/configs/pepe/home-assistant/zigbee2mqtt/doors.nix
Normal file
101
nixos/configs/pepe/home-assistant/zigbee2mqtt/doors.nix
Normal file
|
@ -0,0 +1,101 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/MCCGQ11LM.html
|
||||
allDevices = {
|
||||
"door_sensor_1" = { id = "0x00158d000312dc52"; };
|
||||
"door_sensor_2" = { id = "0x00158d000316d5bf"; };
|
||||
"door_sensor_3" = { id = "0x00158d0002f9516f"; };
|
||||
"door_sensor_4" = { id = "0x00158d00031383b9"; };
|
||||
"door_sensor_5" = { id = "0x00158d0003120d3e"; };
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
])
|
||||
allDevices);
|
||||
|
||||
binary_sensor = lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: {
|
||||
name = name;
|
||||
platform = "mqtt";
|
||||
device_class = "door";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
payload_on = false;
|
||||
payload_off = true;
|
||||
value_template = "{{ value_json.contact}}";
|
||||
})
|
||||
allDevices;
|
||||
|
||||
# create groups
|
||||
# -------------
|
||||
group =
|
||||
let
|
||||
# to have nice panels for every device
|
||||
sensorGroups = lib.mapAttrs
|
||||
(name:
|
||||
{ ... }: {
|
||||
entities = [
|
||||
"binary_sensor.${name}"
|
||||
"sensor.battery_${name}"
|
||||
"sensor.link_${name}"
|
||||
];
|
||||
})
|
||||
allDevices;
|
||||
# sort lights into given groups.
|
||||
sortedInGroups =
|
||||
let
|
||||
groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ groups ? [ ], ... }:
|
||||
map (groupName: { "${groupName}" = "binary_sensor.${name}"; }) groups)
|
||||
allDevices));
|
||||
in
|
||||
lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
in
|
||||
sortedInGroups // sensorGroups // {
|
||||
all_sensors.entities =
|
||||
lib.mapAttrsToList (name: { ... }: "binary_sensor.${name}") allDevices;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
57
nixos/configs/pepe/home-assistant/zigbee2mqtt/fyrtur.nix
Normal file
57
nixos/configs/pepe/home-assistant/zigbee2mqtt/fyrtur.nix
Normal file
|
@ -0,0 +1,57 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/E1757.html
|
||||
allDevices = {
|
||||
"office_fyrtur_1" = { id = "0x680ae2fffe64fa40"; };
|
||||
"office_fyrtur_2" = { id = "0x680ae2fffe91d234"; };
|
||||
"bedroom_fyrtur_1" = { id = "0x680ae2fffe6e9f41"; };
|
||||
"broken_fyrtur_1" = { id = "0x680ae2fffe8f6411"; };
|
||||
};
|
||||
|
||||
# -t "zigbee2mqtt/fyrtur1/set" -m '{"position":100}'
|
||||
# -t "zigbee2mqtt/fyrtur1/set" -m '{"position":15}'
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
transition = 0.1;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
sensor = lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
])
|
||||
allDevices);
|
||||
|
||||
};
|
||||
|
||||
}
|
85
nixos/configs/pepe/home-assistant/zigbee2mqtt/heater.nix
Normal file
85
nixos/configs/pepe/home-assistant/zigbee2mqtt/heater.nix
Normal file
|
@ -0,0 +1,85 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/SPZB0001.html
|
||||
allDevices = {
|
||||
"office_heater_1" = { id = "0x00158d00032f5ee4"; }; # office
|
||||
"office_heater_2" = { id = "0x00158d00032f5f9f"; }; # office (kitchen)
|
||||
"bedroom_heater_1" = { id = "0x00158d00032f6d1e"; }; # bed room
|
||||
"storage_heater_1" = { id = "0x00158d00032f604d"; }; # abstell raum
|
||||
};
|
||||
|
||||
# -t "zigbee2mqtt/heater3/set" -m '{"system_mode":"auto","current_heating_setpoint":23}'
|
||||
# -t "zigbee2mqtt/heater3/set" -m '{"system_mode":"off"}'
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
legacy = false;
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
transition = 1;
|
||||
debounce = 0.5;
|
||||
filtered_attributes = [
|
||||
"battery_low"
|
||||
"eurotronic_host_flags"
|
||||
"eurotronic_system_mode"
|
||||
#"occupied_heating_setpoint"
|
||||
#"pi_heating_demand"
|
||||
#"unoccupied_heating_setpoint"
|
||||
];
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
sensor = lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = "temperature_${name}";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "°C";
|
||||
device_class = "temperature";
|
||||
value_template = "{{ value_json.local_temperature }}";
|
||||
}
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = "pi_heating_demand_${name}";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
value_template = "{{ value_json.pi_heating_demand }}";
|
||||
}
|
||||
])
|
||||
allDevices);
|
||||
|
||||
};
|
||||
|
||||
}
|
48
nixos/configs/pepe/home-assistant/zigbee2mqtt/leds.nix
Normal file
48
nixos/configs/pepe/home-assistant/zigbee2mqtt/leds.nix
Normal file
|
@ -0,0 +1,48 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/GL-C-007-1ID.html
|
||||
allDevices = {
|
||||
"led_1" = { id = "0x00124b001f7a5be9"; };
|
||||
"led_2" = { id = "0x00124b001ee958b3"; };
|
||||
};
|
||||
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"ON","transition":0, "color_temp":255}'
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"OFF","transition":0, "color_temp":255}'
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"ON","brightness":255,"color":{"hex":"#00FFFF"}}'
|
||||
# -t "zigbee2mqtt/led_1/set" -m '{"state":"OFF"}'
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
transition = 1;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
light = lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: {
|
||||
platform = "mqtt";
|
||||
name = name;
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
command_topic = "zigbee2mqtt/${name}/set";
|
||||
value_template = "{{ value_json.click }}";
|
||||
brightness = true;
|
||||
color_temp = true;
|
||||
schema = "json";
|
||||
})
|
||||
allDevices;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -13,9 +13,11 @@ let
|
|||
"light_8" = { id = "0x7cb03eaa0a0384d3"; };
|
||||
};
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
|
@ -23,11 +25,13 @@ in {
|
|||
friendly_name = name;
|
||||
osram_set_transition = 2; # time in seconds (integer or float)
|
||||
};
|
||||
}) allDevices;
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
light = lib.mapAttrsToList (name:
|
||||
light = lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: {
|
||||
platform = "mqtt";
|
||||
name = name;
|
||||
|
@ -38,7 +42,8 @@ in {
|
|||
brightness = true;
|
||||
color_temp = true;
|
||||
schema = "json";
|
||||
}) allDevices;
|
||||
})
|
||||
allDevices;
|
||||
|
||||
# sensor = with lib;
|
||||
# mapAttrsToList (name:
|
76
nixos/configs/pepe/home-assistant/zigbee2mqtt/motion.nix
Normal file
76
nixos/configs/pepe/home-assistant/zigbee2mqtt/motion.nix
Normal file
|
@ -0,0 +1,76 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/RTCGQ01LM.html
|
||||
allDevices = {
|
||||
|
||||
"motion_sensor_1" = { id = "0x00158d0002fbd451"; };
|
||||
"motion_sensor_2" = { id = "0x00158d0002f9a6b8"; };
|
||||
"motion_sensor_3" = { id = "0x00158d0002f04522"; };
|
||||
"motion_sensor_4" = { id = "0x00158d0002f9a558"; };
|
||||
"motion_sensor_5" = { id = "0x00158d0002f9a56f"; };
|
||||
"motion_sensor_6" = { id = "0x00158d0002f9a5cb"; };
|
||||
"motion_sensor_7" = { id = "0x00158d0002f9a6aa"; };
|
||||
"motion_sensor_8" = { id = "0x00158d0002f04637"; };
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, timeout ? 65, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
# should not be set below 60 seconds
|
||||
occupancy_timeout = timeout;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define meta information sensors
|
||||
binary_sensor = lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: [{
|
||||
name = "${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
value_template = "{{ value_json.occupancy }}";
|
||||
#icon = "mdi:battery-10";
|
||||
payload_on = true;
|
||||
payload_off = false;
|
||||
device_class = "motion";
|
||||
}])
|
||||
allDevices);
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: [
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
])
|
||||
allDevices);
|
||||
};
|
||||
}
|
|
@ -9,10 +9,13 @@ let
|
|||
"repeater4" = { id = "0x680ae2fffe8e2e71"; };
|
||||
};
|
||||
|
||||
in {
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs' (name:
|
||||
in
|
||||
{
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = { friendly_name = name; };
|
||||
}) allDevices;
|
||||
})
|
||||
allDevices;
|
||||
}
|
|
@ -26,7 +26,8 @@ let
|
|||
# is copied from the store on startup
|
||||
devices = "devices.yaml";
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.custom.services.zigbee2mqtt = {
|
||||
enable = mkEnableOption "enable zigbee2mqtt service";
|
||||
|
112
nixos/configs/pepe/home-assistant/zigbee2mqtt/temperatur.nix
Normal file
112
nixos/configs/pepe/home-assistant/zigbee2mqtt/temperatur.nix
Normal file
|
@ -0,0 +1,112 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
|
||||
# https://www.zigbee2mqtt.io/devices/WSDCGQ11LM.html
|
||||
allDevices = {
|
||||
"temperature_sensor_1" = {
|
||||
id = "0x00158d0002d79220";
|
||||
groups = [ "living_room" ];
|
||||
};
|
||||
"temperature_sensor_2" = {
|
||||
id = "0x00158d0002d7913d";
|
||||
groups = [ "living_room" ];
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
|
||||
services.zigbee2mqttConfiguration = lib.mapAttrs'
|
||||
(name:
|
||||
{ id, ... }: {
|
||||
name = id;
|
||||
value = {
|
||||
retain = false;
|
||||
friendly_name = name;
|
||||
};
|
||||
})
|
||||
allDevices;
|
||||
|
||||
services.homeAssistantConfig = {
|
||||
|
||||
# define meta information sensors
|
||||
sensor = lib.flatten (lib.mapAttrsToList
|
||||
(name:
|
||||
{ ... }: [
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = name;
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "°C";
|
||||
device_class = "temperature";
|
||||
value_template = "{{ value_json.temperature }}";
|
||||
}
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = "humidity_${name}";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
device_class = "humidity";
|
||||
value_template = "{{ value_json.humidity }}";
|
||||
}
|
||||
#{
|
||||
# platform = "mqtt";
|
||||
# name = "pressure_${name}";
|
||||
# state_topic = "zigbee2mqtt/${name}";
|
||||
# availability_topic = "zigbee2mqtt/bridge/state";
|
||||
# unit_of_measurement = "hPa";
|
||||
# device_class = "pressure";
|
||||
# value_template = "{{ value_json.pressure }}";
|
||||
#}
|
||||
{
|
||||
name = "battery_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
unit_of_measurement = "%";
|
||||
icon = "mdi:battery-10";
|
||||
value_template = "{{ value_json.battery }}";
|
||||
}
|
||||
{
|
||||
name = "link_${name}";
|
||||
platform = "mqtt";
|
||||
state_topic = "zigbee2mqtt/${name}";
|
||||
availability_topic = "zigbee2mqtt/bridge/state";
|
||||
icon = "mdi:signal";
|
||||
unit_of_measurement = "lqi";
|
||||
value_template = "{{ value_json.linkquality }}";
|
||||
}
|
||||
])
|
||||
allDevices);
|
||||
|
||||
# create groups
|
||||
# -------------
|
||||
#group = let
|
||||
# # to have nice panels for every device
|
||||
# sensorGroups = lib.mapAttrs (name:
|
||||
# { ... }: {
|
||||
# entities = [
|
||||
# "sensor.${name}"
|
||||
# "sensor.humidity_${name}"
|
||||
# #"sensor.pressure_${name}"
|
||||
# "sensor.battery_${name}"
|
||||
# "sensor.link_${name}"
|
||||
# ];
|
||||
# }) allDevices;
|
||||
# # sort lights into given groups.
|
||||
# sortedInGroups = let
|
||||
# groupEntries = lib.zipAttrs (lib.flatten (lib.mapAttrsToList (name:
|
||||
# { groups ? [ ], ... }:
|
||||
# map (groupName: { "${groupName}" = "sensor.${name}"; }) groups)
|
||||
# allDevices));
|
||||
# in lib.mapAttrs (name: entities: { inherit entities; }) groupEntries;
|
||||
#in sortedInGroups // sensorGroups // {
|
||||
# all_sensors.entities =
|
||||
# lib.mapAttrsToList (name: { ... }: "sensor.${name}") allDevices;
|
||||
#};
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -5,7 +5,8 @@ let
|
|||
ipAddress = "10.1.0.2";
|
||||
prefixLength = 24;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
networking.extraHosts = ''
|
||||
10.1.0.1 workout.lan
|
92
nixos/configs/pepe/mpd.nix
Normal file
92
nixos/configs/pepe/mpd.nix
Normal file
|
@ -0,0 +1,92 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
services.mpd = {
|
||||
enable = true;
|
||||
network.listenAddress = "any";
|
||||
musicDirectory = "/media/syncthing/music-library";
|
||||
playlistDirectory = "/media/syncthing/music-library/playlists";
|
||||
};
|
||||
|
||||
users.groups."syncthing".members = [ "mpd" ];
|
||||
|
||||
sound.enable = true;
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
6680 # mopidy
|
||||
6600 # mpd
|
||||
1234 # zeroconf
|
||||
];
|
||||
|
||||
users.users."spotifyd" = {
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
sops.secrets.spotify_pass = {
|
||||
owner = "spotifyd";
|
||||
};
|
||||
sops.secrets.spotify_user = {
|
||||
owner = "spotifyd";
|
||||
};
|
||||
|
||||
services.spotifyd.enable = true;
|
||||
services.spotifyd.config = ''
|
||||
[global]
|
||||
username_cmd = "cat ${config.sops.secrets.spotify_user.path}"
|
||||
password_cmd = "cat ${config.sops.secrets.spotify_pass.path}"
|
||||
backend = "alsa" # use portaudio for macOS [homebrew]
|
||||
# The alsa audio device to stream audio to. To get a
|
||||
# list of valid devices, run `aplay -L`,
|
||||
#device = "alsa_audio_device" # omit for macOS
|
||||
# The alsa mixer used by `spotifyd`.
|
||||
mixer = "PCM" # omit for macOS
|
||||
|
||||
# A script that gets evaluated in the user's shell when the song changes [aliases: onevent]
|
||||
on-song-change-hook = "${pkgs.mpc_cli}/bin/mpc --host localhost --port 6600 stop"
|
||||
|
||||
# The volume controller. Each one behaves different to
|
||||
# volume increases. For possible values, run
|
||||
# `spotifyd --help`.
|
||||
volume_controller = "alsa" # use softvol for macOS
|
||||
|
||||
# The name that gets displayed under the connect tab on
|
||||
# official clients. Spaces are not allowed!
|
||||
device_name = "DJane"
|
||||
|
||||
# The audio bitrate. 96, 160 or 320 kbit/s
|
||||
bitrate = 320
|
||||
|
||||
# The directory used to cache audio data. This setting can save
|
||||
# a lot of bandwidth when activated, as it will avoid re-downloading
|
||||
# audio files when replaying them.
|
||||
#
|
||||
# Note: The file path does not get expanded. Environment variables and
|
||||
# shell placeholders like $HOME or ~ don't work!
|
||||
#cache_path = "cache_directory"
|
||||
|
||||
# If set to true, audio data does NOT get cached.
|
||||
no_audio_cache = true
|
||||
|
||||
# Volume on startup between 0 and 100
|
||||
# NOTE: This variable's type will change in v0.4, to a number (instead of string)
|
||||
initial_volume = "90"
|
||||
|
||||
# If set to true, enables volume normalisation between songs.
|
||||
volume_normalisation = false
|
||||
|
||||
# The normalisation pregain that is applied for each song.
|
||||
# normalisation_pregain = -10
|
||||
|
||||
# The port `spotifyd` uses to announce its service over the network.
|
||||
zeroconf_port = 1234
|
||||
|
||||
# The proxy `spotifyd` will use to connect to spotify.
|
||||
#proxy = "http://proxy.example.org:8080"
|
||||
|
||||
# The displayed device type in Spotify clients.
|
||||
# Can be unknown, computer, tablet, smartphone, speaker, t_v,
|
||||
# a_v_r (Audio/Video Receiver), s_t_b (Set-Top Box), and audio_dongle.
|
||||
device_type = "computer"
|
||||
'';
|
||||
|
||||
|
||||
}
|
|
@ -17,12 +17,15 @@
|
|||
#};
|
||||
};
|
||||
|
||||
sops.secrets.syncthing_cert = { };
|
||||
sops.secrets.syncthing_key = { };
|
||||
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
openDefaultPorts = true;
|
||||
declarative = {
|
||||
cert = toString <secrets/syncthing/cert.pem>;
|
||||
key = toString <secrets/syncthing/key.pem>;
|
||||
cert = toString config.sops.secrets.syncthing_cert.path;
|
||||
key = toString config.sops.secrets.syncthing_key.path;
|
||||
|
||||
overrideFolders = true;
|
||||
folders = {
|
24
nixos/configs/pepe/taskwarrior-pushover.nix
Normal file
24
nixos/configs/pepe/taskwarrior-pushover.nix
Normal file
|
@ -0,0 +1,24 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
users.users."taskwarrior-pushover".isSystemUser = true;
|
||||
|
||||
sops.secrets.pushoverApiToken.owner = "taskwarrior-pushover";
|
||||
sops.secrets.pushoverUserKey.owner = "taskwarrior-pushover";
|
||||
sops.secrets.taskwarriorCa.owner = "taskwarrior-pushover";
|
||||
sops.secrets.taskwarriorCertificate.owner = "taskwarrior-pushover";
|
||||
sops.secrets.taskwarriorKey.owner = "taskwarrior-pushover";
|
||||
|
||||
services.taskwarrior-pushover = {
|
||||
enable = true;
|
||||
recurrence = "on";
|
||||
onCalendar = "06:30:00";
|
||||
server = "taskd.ingolf-wagner.de:53589";
|
||||
pushoverApiTokenFile = config.sops.secrets.pushoverApiToken.path;
|
||||
pushoverUserKeyFile = config.sops.secrets.pushoverUserKey.path;
|
||||
caFile = config.sops.secrets.taskwarriorCa.path;
|
||||
certificateFile = config.sops.secrets.taskwarriorCertificate.path;
|
||||
keyFile = config.sops.secrets.taskwarriorKey.path;
|
||||
credentials = "1337/palo/ed0fdbe8-2dc3-408b-84cb-d07d363bccd2";
|
||||
};
|
||||
}
|
|
@ -15,4 +15,7 @@ with lib;
|
|||
};
|
||||
};
|
||||
|
||||
sops.secrets.tinc_retiolum_ed25519_key = { };
|
||||
sops.secrets.tinc_retiolum_rsa_key = { };
|
||||
|
||||
}
|
|
@ -10,7 +10,8 @@ let
|
|||
ssid = "palosiot";
|
||||
wifiPassword = lib.fileContents <secrets/iot_wifi>;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
# todo only open needed ports
|
||||
networking.firewall.trustedInterfaces = [ wifi ];
|
|
@ -27,7 +27,8 @@
|
|||
|
||||
# automount
|
||||
# ---------
|
||||
(let mediaUUID = "3d106f56-89e5-400d-9d6b-1dd957919548";
|
||||
(
|
||||
let mediaUUID = "3d106f56-89e5-400d-9d6b-1dd957919548";
|
||||
in {
|
||||
fileSystems."/media" = {
|
||||
device = "/dev/disk/by-uuid/${mediaUUID}";
|
||||
|
@ -46,7 +47,8 @@
|
|||
what = "/dev/disk/by-uuid/${mediaUUID}";
|
||||
where = "/media";
|
||||
}];
|
||||
})
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
# NTFS support
|
|
@ -54,7 +54,12 @@
|
|||
after = [ "media.mount" ];
|
||||
};
|
||||
|
||||
users.groups."syncthing".members = [ "mpd" "syncthing" "kodi" "palo" ];
|
||||
users.groups."syncthing".members = [
|
||||
"mpd"
|
||||
"syncthing"
|
||||
"kodi"
|
||||
"palo"
|
||||
];
|
||||
|
||||
backup.dirs = [ "/var/lib/syncthing/finance" ];
|
||||
|
|
@ -8,7 +8,8 @@ let
|
|||
ssid = "palosiot";
|
||||
wifiPassword = lib.fileContents <secrets/iot_wifi>;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
# todo only open needed ports
|
||||
networking.firewall.trustedInterfaces = [ wifi ];
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
|
||||
}
|
||||
{ }
|
|
@ -1,25 +1,20 @@
|
|||
{ config, pkgs, lib, ... }: {
|
||||
imports = [
|
||||
|
||||
<system/proxy>
|
||||
../../system/proxy
|
||||
./hardware-configuration.nix
|
||||
|
||||
<system/server/packages.nix>
|
||||
../../system/server/packages.nix
|
||||
./nginx.nix
|
||||
./tinc.nix
|
||||
./codimd.nix
|
||||
./bitwarden.nix
|
||||
#./syncplay.nix
|
||||
./grocy.nix
|
||||
|
||||
];
|
||||
|
||||
nix = {
|
||||
package = pkgs.nixUnstable;
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
};
|
||||
|
||||
sops.defaultSopsFile = ../../secrets/sputnik.yaml;
|
||||
networking.hostName = "sputnik";
|
||||
networking.useDHCP = true;
|
||||
|
||||
|
@ -40,7 +35,7 @@
|
|||
};
|
||||
|
||||
services.custom.ssh.sshd.rootKeyFiles =
|
||||
[ (toString <secrets/ssh/jenkins_rsa.pub>) ];
|
||||
[ ../../assets/ssh/jenkins.pub ];
|
||||
|
||||
# make sure ssh is only available trough the tinc
|
||||
networking.firewall.extraCommands = ''
|
16
nixos/configs/sputnik/grocy.nix
Normal file
16
nixos/configs/sputnik/grocy.nix
Normal file
|
@ -0,0 +1,16 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.grocy = {
|
||||
enable = true;
|
||||
settings = {
|
||||
culture = "de";
|
||||
currency = "EUR";
|
||||
};
|
||||
hostName = "grocy.ingolf-wagner.de";
|
||||
nginx.enableSSL = true;
|
||||
};
|
||||
|
||||
backup.dirs = [ config.services.grocy.dataDir ];
|
||||
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ modulesPath, config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [ <nixpkgs/nixos/modules/profiles/qemu-guest.nix> ];
|
||||
#imports = [ <nixpkgs/nixos/modules/profiles/qemu-guest.nix> ];
|
||||
imports = [ "${modulesPath}/profiles/qemu-guest.nix" ];
|
||||
|
||||
boot.initrd.availableKernelModules =
|
||||
[ "ata_piix" "uhci_hcd" "virtio_pci" "sd_mod" "sr_mod" ];
|
|
@ -3,7 +3,8 @@ let
|
|||
domain = "io.ingolf-wagner.de";
|
||||
publicIp = "195.201.134.247";
|
||||
pw = import <secrets/iodinepw.nix>;
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
services.iodine.server = {
|
||||
enable = true;
|
|
@ -1,6 +1,7 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
|
||||
# todo create flake for this
|
||||
errorPages = pkgs.fetchgit {
|
||||
url = "https://git.ingolf-wagner.de/palo/http-errors.git";
|
||||
rev = "74b8e4c1d9bbba3db6ad858b888e1867318af1f0";
|
||||
|
@ -27,7 +28,8 @@ let
|
|||
root = "${errorPages}/";
|
||||
};
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
networking.firewall.allowedTCPPorts =
|
||||
[ 80 443 4443 config.services.taskserver.listenPort ];
|
||||
|
@ -62,6 +64,7 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
"git.ingolf-wagner.de" = {
|
||||
listen = [
|
||||
{
|
||||
|
@ -115,6 +118,21 @@ in {
|
|||
} // error.locations;
|
||||
};
|
||||
|
||||
"grocy.ingolf-wagner.de" = {
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 4443;
|
||||
ssl = true;
|
||||
}
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 80;
|
||||
ssl = false;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
"paste.ingolf-wagner.de" = {
|
||||
listen = [
|
||||
{
|
||||
|
@ -358,45 +376,6 @@ in {
|
|||
} // error.locations;
|
||||
};
|
||||
|
||||
#"home.ingolf-wagner.de" = {
|
||||
# listen = [
|
||||
# {
|
||||
# addr = "0.0.0.0";
|
||||
# port = 4443;
|
||||
# ssl = true;
|
||||
# }
|
||||
# {
|
||||
# addr = "0.0.0.0";
|
||||
# port = 80;
|
||||
# ssl = false;
|
||||
# }
|
||||
# ];
|
||||
# extraConfig = ''
|
||||
# proxy_buffering off;
|
||||
# # client certificate
|
||||
# ssl_client_certificate ${<secrets/client-cert/ca.crt>};
|
||||
# # make verification optional, so we can display a 403 message to those
|
||||
# # who fail authentication
|
||||
# ssl_verify_client optional;
|
||||
# '';
|
||||
# forceSSL = true;
|
||||
# enableACME = true;
|
||||
# locations."/" = {
|
||||
# proxyPass = "http://pepe.private:8123";
|
||||
# proxyWebsockets = true;
|
||||
# extraConfig = ''
|
||||
# # if the client-side certificate failed to authenticate, show a 403
|
||||
# # message to the client
|
||||
# if ($ssl_client_verify != SUCCESS) {
|
||||
# return 403;
|
||||
# }
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header Upgrade $http_upgrade;
|
||||
# proxy_set_header Connection $connection_upgrade;
|
||||
# '';
|
||||
# };
|
||||
#};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -461,7 +440,8 @@ in {
|
|||
|
||||
systemd.services."socat-taskd" = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = let port = toString config.services.taskserver.listenPort;
|
||||
script =
|
||||
let port = toString config.services.taskserver.listenPort;
|
||||
in ''
|
||||
${pkgs.socat}/bin/socat TCP-LISTEN:${port},fork TCP:workhorse.private:${port}
|
||||
'';
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue