This commit is contained in:
Jeschli 2020-04-14 20:36:21 +02:00
commit e5342b25c1
117 changed files with 2190 additions and 1086 deletions

View File

@ -8,7 +8,7 @@ before_script:
# prepare git fetching of secrets
- echo "$gitlab_deploy_privkey" > ~/.ssh/gitlab_deploy.key
- chmod 600 ~/.ssh/gitlab_deploy.key
- ssh-keyscan -H 'ssh.git.shackspace.de' >> ~/.ssh/known_hosts
- echo "$ssh_git_shackspace_serverkey" >> ~/.ssh/known_hosts
# import secret key for secrets
- echo "$secrets_gpg_key" | gpg --import
deployment test:

6
.gitmodules vendored
View File

@ -7,9 +7,9 @@
[submodule "lass/5pkgs/autowifi"]
path = lass/5pkgs/autowifi
url = https://github.com/Lassulus/autowifi
[submodule "jeschli/2configs/misc-elisp-scripts"]
path = jeschli/2configs/misc-elisp-scripts
url = git@github.com:Jeschli/misc-elisp-scripts.git
[submodule "jeschli/2configs/elisp"]
path = jeschli/2configs/elisp
url = git@github.com:Jeschli/misc-elisp-scripts.git
[submodule "submodules/brockman"]
path = submodules/brockman
url = https://github.com/kmein/brockman.git

View File

@ -4,7 +4,7 @@ let
pkgsWithOverlay = import <nixpkgs-unstable> {
overlays = [
(import (builtins.fetchTarball {
url = https://github.com/nix-community/emacs-overlay/archive/master.tar.gz;
url = https://github.com/nix-community/emacs-overlay/archive/403c14c23be188b58c0b1bc197b428041d8a0cea.tar.gz;
}))
];
};

View File

@ -0,0 +1 @@
LOL

View File

@ -26,14 +26,12 @@
"http://cgit.hotdog.r/krops"
"http://cgit.ni.r/krops"
"http://cgit.prism.r/krops"
"https://git.ingolf-wagner.de/krebs/krops.git"
"https://github.com/krebs/krops.git"
];
nix_writers.urls = [
"http://cgit.hotdog.r/nix-writers"
"http://cgit.ni.r/nix-writers"
"http://cgit.prism.r/nix-writers"
"https://git.ingolf-wagner.de/krebs/nix-writers.git"
];
stockholm.urls = [
"http://cgit.enklave.r/stockholm"

View File

@ -6,12 +6,13 @@
platform = "homeassistant";
event = "start";
};
# trigger good/bad air
action = [
{ service = "light.turn_on";
data = {
entity_id = "light.fablab_led";
effect = "Rainbow";
color_name = "yellow";
color_name = "purple";
};
}
];

View File

@ -0,0 +1,82 @@
# needs:
# binary_sensor.portal_lock
# sensor.keyholder
# media_player.lounge
let
glados = import ../lib;
in
[
{
alias = "Greet new keyholder for key exchange";
initial_state = true;
trigger = {
platform = "state";
entity_id = "sensor.keyholder";
};
condition = {
condition = "template";
value_template = "{{ trigger.from_state.state != 'No Keyholder' }}";
};
action = glados.say.kiosk "Danke {{trigger.to_state.state}} für das Übernehmen des Keys von {{trigger.from_state.state}}";
# action = [];
}
{
alias = "Start Music on portal lock on";
# TODO: use "power" trigger
trigger = {
platform = "state";
entity_id = "binary_sensor.portal_lock";
to = "on";
for.seconds = 30;
};
condition = {
condition = "and";
conditions =
[
{ # only start if a keyholder opened the door and if the lounge mpd is currently not playing anything
condition = "template";
value_template = "{{ state('sensor.keyholder') != 'No Keyholder' }}";
}
{
condition = "state";
entity_id = "media_player.lounge";
state = "idle";
}
];
};
action = [
{
service = "media_player.volume_set";
data = {
entity_id = "media_player.lounge";
volume_level = 1.0;
};
}
{
service = "media_player.play_media";
data = {
entity_id = "media_player.lounge";
media_content_type = "playlist";
media_content_id = "ansage";
};
}
{ delay.seconds = 8; }
{
service = "media_player.volume_set";
data = {
entity_id = "media_player.lounge";
volume_level = 0.6;
};
}
{
service = "media_player.play_media";
data = {
entity_id = "media_player.lounge";
media_content_type = "playlist";
media_content_id = "lassulus superradio";
};
}
];
}
]

View File

@ -39,7 +39,7 @@ in {
'';
})).override {
extraPackages = ps: with ps; [
python-forecastio jsonrpc-async jsonrpc-websocket mpd2
python-forecastio jsonrpc-async jsonrpc-websocket mpd2 pkgs.picotts
];
};
autoExtraComponents = true;
@ -76,6 +76,8 @@ in {
client_id = "home-assistant";
keepalive = 60;
protocol = 3.1;
discovery = true; #enable esphome discovery
discovery_prefix = "homeassistant";
birth_message = {
topic = "glados/hass/status/LWT";
payload = "Online";
@ -89,21 +91,34 @@ in {
retain = true;
};
};
switch = wasser.switch;
light = badair.light;
switch =
wasser.switch
++ (import ./switch/power.nix)
;
light = [];
media_player = [
{ platform = "mpd";
name = "lounge";
host = "lounge.mpd.shack";
}
{ platform = "mpd";
name = "kiosk";
host = "lounge.kiosk.shack";
}
];
sensor =
(import ./sensors/hass.nix)
++ (import ./sensors/power.nix)
(import ./sensors/power.nix)
++ (import ./sensors/mate.nix)
++ (import ./sensors/darksky.nix { inherit lib;})
++ shackopen.sensor
++ badair.sensor;
;
air_quality = (import ./sensors/sensemap.nix );
binary_sensor = shackopen.binary_sensor;
binary_sensor =
shackopen.binary_sensor
++ (import ./sensors/spaceapi.nix)
;
camera = [];
@ -117,19 +132,27 @@ in {
#conversation = {};
history = {};
logbook = {};
logger = {
default = "info";
};
recorder = {};
tts = [
{ platform = "google_translate";
service_name = "say";
language = "de";
cache = true;
time_memory = 57600;
}
{ platform = "picotts";
language = "de-DE";
service_name = "pico";
}
#{ platform = "picotts";
# language = "de-DE";
#}
];
sun = {};
automation = wasser.automation
++ badair.automation
++ (import ./automation/shack-startup.nix)
++ (import ./automation/hass-restart.nix);
device_tracker = [];

View File

@ -2,89 +2,48 @@ let
prefix = "glados";
in
{
esphome =
say = let
# returns a list of actions to be performed on an mpd to say something
tts = { message, entity }:
[
{
service = "media_player.turn_on";
data.entity_id = "media_player.${entity}";
}
{ service = "media_player.play_media";
data = {
entity_id = "media_player.${entity}";
media_content_type = "playlist";
media_content_id = "ansage";
};
}
{
service = "media_player.turn_on";
data.entity_id = "media_player.${entity}";
}
{ delay.seconds = 8; }
{ service = "tts.say";
entity_id = "media_player.${entity}";
data_template = {
inherit message;
language = "de";
};
}
];
in
{
temp = {host, topic ? "temperature" }:
{
platform = "mqtt";
name = "${host} Temperature";
device_class = "temperature";
unit_of_measurement = "°C";
icon = "mdi:thermometer";
state_topic = "${prefix}/${host}/sensor/${topic}/state";
availability_topic = "${prefix}/${host}/status";
payload_available = "online";
payload_not_available = "offline";
lounge = message: tts {
inherit message;
entity = "lounge";
};
hum = {host, topic ? "humidity" }:
{
platform = "mqtt";
unit_of_measurement = "%";
icon = "mdi:water-percent";
device_class = "humidity";
name = "${host} Humidity";
state_topic = "${prefix}/${host}/sensor/${topic}/state";
availability_topic = "${prefix}/${host}/status";
payload_available = "online";
payload_not_available = "offline";
herrenklo = message: tts {
inherit message;
entity = "herrenklo";
};
# copied from "homeassistant/light/fablab_led/led_ring/config"
led = {host, topic ? "led", name ? host}:
{ # name: fablab_led
# topic: led_ring
platform = "mqtt";
inherit name;
schema = "json";
brightness = true;
rgb = true;
effect = true;
effect_list = [ # TODO: may be different
"Random"
"Strobe"
"Rainbow"
"Color Wipe"
"Scan"
"Twinkle"
"Fireworks"
"Addressable Flicker"
"None"
];
state_topic = "${prefix}/${host}/light/${topic}/state";
command_topic = "${prefix}/${host}/light/${topic}/command";
availability_topic = "${prefix}/${host}/status";
payload_available = "online";
payload_not_available = "offline";
qos = 1;
};
# Feinstaub
dust_25m = { host, name ? "${host} < 2.5µm", topic ? "particulate_matter_25m_concentration" }:
{
platform = "mqtt";
unit_of_measurement = "µg/m³";
icon = "mdi:chemical-weapon";
inherit name;
state_topic = "${prefix}/${host}/sensor/${topic}/state";
availability_topic = "${prefix}/${host}/status";
};
dust_100m = {host, name ? "${host} < 10µm", topic ? "particulate_matter_100m_concentration" }:
{
platform = "mqtt";
unit_of_measurement = "µg/m³";
icon = "mdi:chemical-weapon";
inherit name;
state_topic = "${prefix}/${host}/sensor/${topic}/state";
availability_topic = "${prefix}/${host}/status";
};
switch = {host, name ? "${host} Button", topic ? "btn" }:
# host: ampel
# name: Button 1
# topic: btn1
{
inherit name;
platform = "mqtt";
state_topic = "${prefix}/${host}/sensor/${topic}/state";
command_topic = "${prefix}/${host}/switch/${topic}/state";
availability_topic = "${prefix}/${host}/status";
kiosk = message: tts {
inherit message;
entity = "kiosk";
};
};
tasmota =

View File

@ -0,0 +1,13 @@
let
glados = import ../lib;
in
{
# LED
light = [
];
sensor = [
];
automation =
[
];
}

View File

@ -2,20 +2,6 @@ let
glados = import ../lib;
in
{
# LED
light = [
(glados.esphome.led { name = "Fablab LED"; host = "fablab_led"; topic = "led_ring"; })
(glados.esphome.led { name = "Fablab LED Part A"; host = "fablab_led"; topic = "A";})
(glados.esphome.led { name = "Fablab LED Part B"; host = "fablab_led"; topic = "B";})
(glados.esphome.led { name = "Fablab LED Part C"; host = "fablab_led"; topic = "C";})
(glados.esphome.led { name = "Fablab LED Part D"; host = "fablab_led"; topic = "D";})
];
sensor = [
(glados.esphome.temp { host = "fablab_feinstaub";})
(glados.esphome.dust_25m { host = "fablab_feinstaub";})
(glados.esphome.dust_100m { host = "fablab_feinstaub";})
];
automation =
[
{ alias = "Gute Luft Fablab";

View File

@ -0,0 +1,21 @@
{lib,...}:
[
{ platform = "darksky";
api_key = lib.removeSuffix "\n"
(builtins.readFile <secrets/hass/darksky.apikey>);
language = "de";
monitored_conditions = [
"summary" "icon"
"nearest_storm_distance" "precip_probability"
"precip_intensity"
"temperature" # "temperature_high" "temperature_low"
"apparent_temperature"
"hourly_summary" # next 24 hours text
"humidity"
"pressure"
"uv_index"
];
units = "si" ;
scan_interval = "00:15:00";
}
]

View File

@ -1,5 +0,0 @@
let
glados = import ../lib;
in
(map (host: glados.esphome.temp {inherit host;}) [ "lounge" "werkstatt" "herrenklo" "dusche" "fablab" "whc" ])
++ (map (host: glados.esphome.hum {inherit host;}) [ "lounge" "werkstatt" "herrenklo" "dusche" "fablab" "whc" ])

View File

@ -0,0 +1,16 @@
let
fuellstand = name: id: {
platform = "rest";
resource = "https://ora5.tutschonwieder.net/ords/lick_prod/v1/get/fuellstand/1/${toString id}";
method = "GET";
name = "Füllstand ${name}";
value_template = "{{ value_json.fuellstand }}";
};
in [
(fuellstand "Wasser" 1)
(fuellstand "Mate Cola" 2)
(fuellstand "Apfelschorle" 3)
(fuellstand "Zitronensprudel" 4)
(fuellstand "Mate 1" 26)
(fuellstand "Mate 2" 27)
]

View File

@ -2,7 +2,6 @@ let
power_x = name: phase:
{ platform = "mqtt";
name = "${phase} ${name}";
# device_class = "power";
state_topic = "/power/total/${phase}/${name}";
availability_topic = "/power/lwt";
payload_available = "Online";
@ -11,17 +10,17 @@ let
power_consumed =
{ platform = "mqtt";
name = "Power Consumed";
#device_class = "power";
device_class = "power";
state_topic = "/power/total/consumed";
availability_topic = "/power/lwt";
payload_available = "Online";
payload_not_available = "Offline";
};
power_volt = power_x "Voltage";
power_watt = power_x "Power";
power_watt = (power_x "Power") ;
power_curr = power_x "Current";
in
(map power_volt [ "L1" "L2" "L3" ])
++ (map power_watt [ "L1" "L2" "L3" ])
++ (map (x: ((power_watt x) // { device_class = "power"; })) [ "L1" "L2" "L3" ])
++ (map power_curr [ "L1" "L2" "L3" ])
++ [ power_consumed ]

View File

@ -0,0 +1,6 @@
[
{
platform = "opensensemap";
station_id = "56a0de932cb6e1e41040a68b";
}
]

View File

@ -0,0 +1,52 @@
[
{
platform = "rest";
resource = "https://spaceapi.afra-berlin.de/v1/status.json";
method = "GET";
name = "Door AFRA Berlin";
device_class = "door";
value_template = "{{ value_json.open }}";
}
{
platform = "rest";
resource = "http://club.entropia.de/spaceapi";
method = "GET";
name = "Door Entropia";
device_class = "door";
value_template = "{{ value_json.open }}";
}
{
platform = "rest";
resource = "http://www.c-base.org/status.json";
method = "GET";
name = "Door C-Base Berlin";
device_class = "door";
value_template = "{{ value_json.open }}";
}
{
platform = "rest";
resource = "https://status.raumzeitlabor.de/api/full.json";
method = "GET";
name = "Door RZL";
device_class = "door";
value_template = "{{ value_json.status }}";
}
{
platform = "rest";
resource = "https://datenobservatorium.de/";
method = "GET";
name = "Door Datenobservatorium";
device_class = "door";
value_template = "false";
scan_interval = 2592000;
}
{
platform = "rest";
resource = "https://infuanfu.de/";
method = "GET";
name = "Door Infuanfu";
device_class = "door";
value_template = "false";
scan_interval = 2592000;
}
]

View File

@ -0,0 +1,6 @@
{
controllers = {
host = "unifi.shack";
site = "shackspace";
};
}

View File

@ -0,0 +1,32 @@
# 1 - haupt
# 2 - dusche
# 3 - warmwasser
# 4 - or
# 5 - kueche
let
nodelight = type: ident: name: {
platform = "mqtt";
name = "${type} ${name}";
command_topic = "${type}/${toString ident}/command";
state_topic = "${type}/${toString ident}/state";
payload_on = "on";
payload_off = "off";
};
power = nodelight "power";
light = ident: name: { icon = "mdi:lightbulb";} // nodelight "light" ident name;
in
[
(power 1 "Hauptschalter")
(power 2 "Dusche")
(power 3 "Warmwasser")
(power 4 "Optionsräume")
(power 5 "Küche")
(light 1 "Decke Lounge 1")
(light 2 "Decke Lounge 2")
(light 3 "Decke Lounge 3")
(light 4 "Decke Lounge 4")
(light 5 "Decke Lounge 5")
(light 6 "Decke Lounge 6")
(light 7 "Decke Lounge 7")
(light 8 "Decke Lounge 8")
]

View File

@ -4,8 +4,9 @@ let
pkg = pkgs.callPackage (
pkgs.fetchgit {
url = "https://git.shackspace.de/rz/muellshack";
rev = "c3d1f70325e5b90f280c5be60110e14f4de653ae";
sha256 = "1dd4kqwdr4v413rmkvmyjzzvw8id9747nifp96pg0c2cy6bhzj24";
rev = "dc80cf1edaa3d86ec2bebae8596ad1d4c4e3650a";
sha256 = "1yipr66zhrg5m20pf3rzvgvvl78an6ddkq6zc45rxb2r0i7ipkyh";
}) { mkYarnPackage = pkgs.yarn2nix-moretea.mkYarnPackage; };
home = "/var/lib/muellshack";
port = "8081";

View File

@ -4,9 +4,9 @@ let
pkg = pkgs.callPackage (
pkgs.fetchgit {
url = "https://git.shackspace.de/rz/node-light.git";
rev = "9c3fe451897cf170fb192a2643180fdfe22388e8";
sha256 = "1zsc38idg452r8wpcna5m3yqx0ri11bd1bw60bl0kpz96dqqnyba";
}) { mkYarnPackage = pkgs.yarn2nix-moretea.mkYarnPackage; };
rev = "90a9347b73af3a9960bd992e6293b357226ef6a0";
sha256 = "1av9w3w8aknlra25jw6gqxzbb01i9kdlfziy29lwz7mnryjayvwk";
}) { };
home = "/var/lib/node-light";
port = "8082";
in {

View File

@ -52,7 +52,7 @@ let
"${url}",
workdir='${name}-${elemAt(splitString "." url) 1}', branches=True,
project='${name}',
pollinterval=10
pollinterval=100
)
)
'') repo.urls)

View File

@ -50,7 +50,6 @@ let
./secret.nix
./setuid.nix
./shadow.nix
./syncthing.nix
./tinc.nix
./tinc_graphs.nix
./urlwatch.nix

View File

@ -144,24 +144,24 @@ in {
};
};
};
idontcare = {
herbert = {
owner = config.krebs.users.Mic92;
nets = rec {
retiolum = {
addrs = [
config.krebs.hosts.idontcare.nets.retiolum.ip4.addr
config.krebs.hosts.idontcare.nets.retiolum.ip6.addr
config.krebs.hosts.herbert.nets.retiolum.ip4.addr
config.krebs.hosts.herbert.nets.retiolum.ip6.addr
];
ip4.addr = "10.243.29.177";
aliases = [ "idontcare.r" ];
aliases = [ "herbert.r" ];
tinc.pubkey = ''
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAxmmbQLVXcnCU9Vg9TCoJxfq/RyNfzaTj8XJsn4Kpo3CvQOwFzL6O
qZnbG55WjPjPumuFgtUdHA/G8mgtrTVaIRbVE9ck2l2wWFzMWxORzuvDbMh5xP8A
OW2Z2qjlH6O9GTBCzpYyHuyBWCjtiN4x9zEqxkIsBARKOylAoy3zQIiiQF0d72An
lqKFi9vYUU90zo9rP8BTzx2ZsEWb28xhHUlwf1+vgaOHI1jI99gnr12dVYl/i/Hb
O28gDUogfpP/5pWFAHJ+53ZscHo8/Y7imjiKgGXmOHywoXOsKQ67M6ROEU/0xPnw
jKmq2p7zTJk2mDhphjePi5idd5yKNX5Q3wIDAQAB
MIIBCgKCAQEA7ZINr8YxVwHtcOR+ySpc9UjnJWsFXlOyu3CnrJ8IrY+mPA25UmNZ
stXd8QbJuxpad9HyPs294uW8UmXttEZzIwAlikVHasM5IQHVltudTTFvv7s3YFWd
/lgpHbo8zOA2mafx+Sr02Fy/lHjk6BTf8IOzdJIpUHZL/P+FUl9baBwGLmtbEvPh
fbvtf5QryBjJ9nRnb+wsPVpeFE/LncIMK/bYQsyE01T5QDu/muAaeYPbgm6FqaQH
OJ4oEHsarWBvU1qzgz/IRz0BHHeTrbbP3AG/glTwL02Z1mtTXSjME7cfk7ZRM5Cj
jXAqnqu2m1B08Kii+zYp4BPZDmPLT5gq+QIDAQAB
-----END RSA PUBLIC KEY-----
'';
};

View File

@ -19,6 +19,10 @@ let
type = types.str;
default = "irc.freenode.org";
};
message = mkOption {
type = types.str;
default = "SSH Hidden Service at ";
};
};
imp = let
@ -50,7 +54,7 @@ let
${pkgs.irc-announce}/bin/irc-announce \
${cfg.server} 6667 ${config.krebs.build.host.name}-ssh \
\${cfg.channel} \
"SSH Hidden Service at $(cat ${hiddenServiceDir}/hostname)"
"${cfg.message}$(cat ${hiddenServiceDir}/hostname)"
'';
PrivateTmp = "true";
User = "tor";

View File

@ -164,12 +164,14 @@ in {
ci = true;
extraZones = {
"krebsco.de" = ''
bookmark.euer IN A ${nets.internet.ip4.addr}
boot IN A ${nets.internet.ip4.addr}
boot.euer IN A ${nets.internet.ip4.addr}
cache.euer IN A ${nets.internet.ip4.addr}
cache.gum IN A ${nets.internet.ip4.addr}
cgit.euer IN A ${nets.internet.ip4.addr}
dl.euer IN A ${nets.internet.ip4.addr}
dns.euer IN A ${nets.internet.ip4.addr}
dockerhub IN A ${nets.internet.ip4.addr}
euer IN A ${nets.internet.ip4.addr}
euer IN MX 1 aspmx.l.google.com.
@ -178,7 +180,11 @@ in {
gold IN A ${nets.internet.ip4.addr}
graph IN A ${nets.internet.ip4.addr}
gum IN A ${nets.internet.ip4.addr}
io IN NS gum.krebsco.de.
iso.euer IN A ${nets.internet.ip4.addr}
board.euer IN A ${nets.internet.ip4.addr}
rss.euer IN A ${nets.internet.ip4.addr}
mediengewitter IN CNAME over.dose.io.
mon.euer IN A ${nets.internet.ip4.addr}
netdata.euer IN A ${nets.internet.ip4.addr}
nixos.unstable IN CNAME krebscode.github.io.
@ -189,9 +195,6 @@ in {
wg.euer IN A ${nets.internet.ip4.addr}
wiki.euer IN A ${nets.internet.ip4.addr}
wikisearch IN A ${nets.internet.ip4.addr}
bookmark.euer IN A ${nets.internet.ip4.addr}
io IN NS gum.krebsco.de.
mediengewitter IN CNAME over.dose.io.
'';
};
cores = 8;
@ -201,7 +204,6 @@ in {
ip6.addr = "2a01:4f8:191:12f6::2";
aliases = [
"gum.i"
"nextgum.i"
];
};
wiregrill = {
@ -237,6 +239,7 @@ in {
"tracker.makefu.r"
"wiki.gum.r"
"wiki.makefu.r"
"warrior.gum.r"
"sick.makefu.r"
];
};

View File

@ -1 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPTBGboU/P00yYiwYje53G0oqDFWmcSJ+hIpMsl4f/HH
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIujMZ3ZFxKpWeB/cjfKfYRr77+VRZk0Eik+92t03NoA

View File

@ -17,21 +17,6 @@ let
default = "/var/realwallpaper/";
};
nightmap = mkOption {
type = types.str;
default = "http://eoimages.gsfc.nasa.gov/images/imagerecords/55000/55167/earth_lights_lrg.jpg";
};
daymap = mkOption {
type = types.str;
default = "https://www.nnvl.noaa.gov/images/globaldata/SnowIceCover_Daily.png";
};
cloudmap = mkOption {
type = types.str;
default = "http://home.megapass.co.kr/~holywatr/cloud_data/clouds_2048.jpg";
};
marker = mkOption {
type = types.str;
default = "http://graph.r/marker.json";
@ -60,6 +45,7 @@ let
path = with pkgs; [
xplanet
imagemagick
inkscape
curl
file
jq
@ -67,9 +53,6 @@ let
environment = {
working_dir = cfg.workingDir;
nightmap_url = cfg.nightmap;
daymap_url = cfg.daymap;
cloudmap_url = cfg.cloudmap;
marker_url = cfg.marker;
};

View File

@ -1,206 +0,0 @@
{ config, pkgs, ... }: with import <stockholm/lib>;
let
kcfg = config.krebs.syncthing;
scfg = config.services.syncthing;
devices = mapAttrsToList (name: peer: {
name = name;
deviceID = peer.id;
addresses = peer.addresses;
}) kcfg.peers;
folders = mapAttrsToList ( _: folder: {
inherit (folder) path id type;
devices = map (peer: { deviceId = kcfg.peers.${peer}.id; }) folder.peers;
rescanIntervalS = folder.rescanInterval;
fsWatcherEnabled = folder.watch;
fsWatcherDelayS = folder.watchDelay;
ignoreDelete = folder.ignoreDelete;
ignorePerms = folder.ignorePerms;
}) kcfg.folders;
getApiKey = pkgs.writeDash "getAPIKey" ''
${pkgs.libxml2}/bin/xmllint \
--xpath 'string(configuration/gui/apikey)'\
${scfg.configDir}/config.xml
'';
updateConfig = pkgs.writeDash "merge-syncthing-config" ''
set -efu
# XXX this assumes the GUI address to be "IPv4 address and port"
host=${shell.escape (elemAt (splitString ":" scfg.guiAddress) 0)}
port=${shell.escape (elemAt (splitString ":" scfg.guiAddress) 1)}
# wait for service to restart
${pkgs.untilport}/bin/untilport "$host" "$port"
API_KEY=$(${getApiKey})
_curl() {
${pkgs.curl}/bin/curl \
-Ss \
-H "X-API-Key: $API_KEY" \
"http://$host:$port/rest""$@"
}
old_config=$(_curl /system/config)
new_config=${shell.escape (toJSON {
inherit devices folders;
})}
new_config=$(${pkgs.jq}/bin/jq -en \
--argjson old_config "$old_config" \
--argjson new_config "$new_config" \
'
$old_config * $new_config
${optionalString (!kcfg.overridePeers) ''
* { devices: $old_config.devices }
''}
${optionalString (!kcfg.overrideFolders) ''
* { folders: $old_config.folders }
''}
'
)
echo $new_config | _curl /system/config -d @-
_curl /system/restart -X POST
'';
in
{
options.krebs.syncthing = {
enable = mkEnableOption "syncthing-init";
cert = mkOption {
type = types.nullOr types.absolute-pathname;
default = null;
};
key = mkOption {
type = types.nullOr types.absolute-pathname;
default = null;
};
overridePeers = mkOption {
type = types.bool;
default = true;
description = ''
Whether to delete the peers which are not configured via the peers option
'';
};
peers = mkOption {
default = {};
type = types.attrsOf (types.submodule ({
options = {
# TODO make into addr + port submodule
addresses = mkOption {
type = types.listOf types.str;
default = [];
};
#TODO check
id = mkOption {
type = types.str;
};
};
}));
};
overrideFolders = mkOption {
type = types.bool;
default = true;
description = ''
Whether to delete the folders which are not configured via the peers option
'';
};
folders = mkOption {
default = {};
type = types.attrsOf (types.submodule ({ config, ... }: {
options = {
path = mkOption {
type = types.absolute-pathname;
default = config._module.args.name;
};
id = mkOption {
type = types.str;
default = config._module.args.name;
};
peers = mkOption {
type = types.listOf types.str;
default = [];
};
rescanInterval = mkOption {
type = types.int;
default = 3600;
};
type = mkOption {
type = types.enum [ "sendreceive" "sendonly" "receiveonly" ];
default = "sendreceive";
};
watch = mkOption {
type = types.bool;
default = true;
};
watchDelay = mkOption {
type = types.int;
default = 10;
};
ignoreDelete = mkOption {
type = types.bool;
default = false;
};
ignorePerms = mkOption {
type = types.bool;
default = true;
};
};
}));
};
};
config = mkIf kcfg.enable {
systemd.services.syncthing = mkIf (kcfg.cert != null || kcfg.key != null) {
serviceConfig.PermissionsStartOnly = mkDefault true;
preStart = ''
${optionalString (kcfg.cert != null) ''
cp ${toString kcfg.cert} ${scfg.configDir}/cert.pem
chown ${scfg.user}:${scfg.group} ${scfg.configDir}/cert.pem
chmod 400 ${scfg.configDir}/cert.pem
''}
${optionalString (kcfg.key != null) ''
cp ${toString kcfg.key} ${scfg.configDir}/key.pem
chown ${scfg.user}:${scfg.group} ${scfg.configDir}/key.pem
chmod 400 ${scfg.configDir}/key.pem
''}
'';
};
systemd.services.syncthing-init = {
after = [ "syncthing.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = scfg.user;
RemainAfterExit = true;
Type = "oneshot";
ExecStart = updateConfig;
};
};
};
}

View File

@ -0,0 +1,19 @@
{ stdenv, fetchzip, makeWrapper, jre }:
stdenv.mkDerivation {
name = "grib2json";
src = fetchzip {
url = "https://github.com/krebs/grib2json-bin/archive/31efe677b40fe491c988d50f96b59b1b7e2d46f7.zip";
sha256 = "1h3yxg270bvac7kaqsbsv4f8nln1i03rfz4cm8cp7llhjj3s6a6b";
};
installPhase = ''
mkdir -p $out/bin
cp -r lib $out/
cat > $out/bin/grib2json << EOF
#!/bin/sh
set -x
${jre}/bin/java -jar $out/lib/grib2json-0.8.0-SNAPSHOT.jar "\$@"
EOF
chmod +x $out/bin/grib2json
'';
}

View File

@ -24,7 +24,12 @@ pkgs.writeDashBin "irc-announce" ''
# echo2 and cat2 are used output to both, stdout and stderr
# This is used to see what we send to the irc server. (debug output)
echo2() { echo "$*"; echo "$*" >&2; }
cat2() { (read x ; echo "$x" ; echo "$x" >&2) }
cat2() {
awk '{
print $0
print $0 > "/dev/stderr"
}'
}
# privmsg_cat transforms stdin to a privmsg
privmsg_cat() { awk '{ print "PRIVMSG "ENVIRON["IRC_CHANNEL"]" :"$0 }'; }

View File

@ -0,0 +1,43 @@
{ writers, coreutils, grib2json, curl, jq, findutils, imagemagick }:
writers.writeDashBin "nomads-cloud" ''
prefix=$(mktemp -d)
grib_path=$prefix.grib
json_path=$prefix.json
pgm_path=$prefix.pgm
png_path="$1"
mkdir -p "$prefix"
date=$(${coreutils}/bin/date +%Y%m%d)
for hour in 18 12 06 00; do
url="https://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p25_1hr.pl?file=gfs.t''${hour}z.pgrb2.0p25.anl&lev_entire_atmosphere_%5C%28considered_as_a_single_layer%5C%29=on&var_CWAT=on&leftlon=-180&rightlon=180&toplat=90&bottomlat=-90&dir=%2Fgfs.$date%2F$hour"
${curl}/bin/curl -fsS "$url" > "$grib_path"
if [ "$?" -eq 0 ]; then
break
fi
done
${grib2json}/bin/grib2json --data "$grib_path" > "$json_path"
width=$(${jq}/bin/jq '.[0].header.nx' < "$json_path")
height=$(${jq}/bin/jq '.[0].header.ny' < "$json_path")
# The maximum gray value. Must be bigger than 0 and less than 65536.
maxval=1000
# pgm - Netpbm grayscale image format
# http://netpbm.sourceforge.net/doc/pgm.html
{
echo P2
echo "$width $height"
echo "$maxval"
cat "$json_path" |
${jq}/bin/jq --argjson maxval "$maxval" -c '
((.[0].data[]) * $maxval | round)
' |
${findutils}/bin/xargs -n "$width"
} > "$pgm_path"
${imagemagick}/bin/convert -roll +50% "$pgm_path" "$png_path"
rm -r "$prefix"
''

View File

@ -1,5 +1,5 @@
{ pkgs, ... }:
pkgs.writeDashBin "generate-wallpaper" ''
pkgs.writers.writeDashBin "generate-wallpaper" ''
set -euf
# usage: getimg FILENAME URL
@ -17,24 +17,28 @@ pkgs.writeDashBin "generate-wallpaper" ''
fi
}
# usage: image_size FILENAME
image_size() {
identify "$1" | awk '{print$3}'
# check if file exists and fetch only if missing
fetch_once() {
name=$1
url=$2
test -e "$name" || fetch "$name" "$url"
}
# usage: make_mask DST SRC MASK
make_layer() {
if needs_rebuild "$@"; then
echo "make $1 (apply mask)" >&2
convert "$2" "$3" -alpha off -compose copy_opacity -composite "$1"
fetch_older_min() {
min=$1
name=$2
url=$3
if ! test "$(find $name -mmin -$min)"; then
fetch "$name" "$url"
fi
}
# usage: flatten DST HILAYER LOLAYER
flatten() {
if needs_rebuild "$@"; then
echo "make $1 (flatten)" >&2
composite "$2" "$3" "$1"
fetch_older_days() {
days=$1
name=$2
url=$3
if ! test "$(find $name -mtime -$days)"; then
fetch "$name" "$url"
fi
}
@ -48,9 +52,11 @@ pkgs.writeDashBin "generate-wallpaper" ''
else
result=1
for b; do
if test "$b" -nt "$a"; then
#echo " $b is newer than $a" >&2
result=0
if check_type "$b" image; then
if test "$b" -nt "$a"; then
#echo " $b is newer than $a" >&2
result=0
fi
fi
done
fi
@ -60,34 +66,67 @@ pkgs.writeDashBin "generate-wallpaper" ''
return $result
}
get_neo_url() {
url=$1
curl -Ss "$url" | grep '3600 x 1800' | sed 's/.*href="\([^"]*\)".*/\1/'
}
main() {
cd "$working_dir"
# fetch source images in parallel
fetch nightmap-raw.jpg \
"$nightmap_url" &
fetch daymap-raw.png \
"$daymap_url" &
fetch clouds-raw.jpg \
"$cloudmap_url" &
fetch marker.json \
"$marker_url" &
fetch_once nightmap-raw.jpg \
'https://eoimages.gsfc.nasa.gov/images/imagerecords/144000/144898/BlackMarble_2016_3km.jpg' &
fetch_once daymap-raw.tif \
'https://eoimages.gsfc.nasa.gov/images/imagerecords/57000/57752/land_shallow_topo_8192.tif' &
fetch_once mercury-raw.svg \
'https://upload.wikimedia.org/wikipedia/commons/2/2e/Mercury_symbol.svg' &
fetch_once venus-raw.svg \
'https://upload.wikimedia.org/wikipedia/commons/6/66/Venus_symbol.svg' &
fetch_once mars-raw.svg \
'https://upload.wikimedia.org/wikipedia/commons/b/b7/Mars_symbol.svg' &
fetch_once jupiter-raw.svg \
'https://upload.wikimedia.org/wikipedia/commons/2/26/Jupiter_symbol.svg' &
fetch_once saturn-raw.svg \
'https://upload.wikimedia.org/wikipedia/commons/7/74/Saturn_symbol.svg' &
fetch_once uranus-raw.svg \
'https://upload.wikimedia.org/wikipedia/commons/f/f1/Uranus_symbol.svg' &
fetch_once neptune-raw.svg \
'https://upload.wikimedia.org/wikipedia/commons/4/47/Neptune_symbol.svg' &
fetch_once krebs-raw.svg \
'https://raw.githubusercontent.com/krebs/painload/master/cholerab/bling/krebs_aquarium.svg' &
fetch_older_min 720 ice-raw.jpg $(get_neo_url \
'https://neo.sci.gsfc.nasa.gov/view.php?datasetId=NISE_D') &
fetch_older_days 3 snow-raw.jpg $(get_neo_url \
'https://neo.sci.gsfc.nasa.gov/view.php?datasetId=MOD10C1_E_SNOW') &
fetch_older_days 7 chlora-raw.jpg $(get_neo_url \
'https://neo.sci.gsfc.nasa.gov/view.php?datasetId=MY1DMM_CHLORA') &
fetch_older_days 3 fire-raw.jpg $(get_neo_url \
'https://neo.sci.gsfc.nasa.gov/view.php?datasetId=MOD14A1_E_FIRE') &
# regular fetches
fetch marker.json "$marker_url" &
fetch sun-raw.jpg 'https://sdo.gsfc.nasa.gov/assets/img/latest/latest_512_0171.jpg' &
wait
check_type nightmap-raw.jpg image
check_type daymap-raw.png image
check_type clouds-raw.jpg image
# fetch clouds if they are older than 3h
if ! test "$(find clouds-raw.png -mmin -180)"; then
${pkgs.nomads-cloud}/bin/nomads-cloud clouds-raw.png
fi
in_size=2048x1024
xplanet_out_size=1466x1200
out_geometry=1366x768+100+160
nightsnow_color='#0c1a49' # nightmap
in_size=3600x1800
xplanet_out_size=3200x2500
out_geometry=3200x1800+0+350
for raw in \
nightmap-raw.jpg \
daymap-raw.png \
clouds-raw.jpg \
daymap-raw.tif \
chlora-raw.jpg \
clouds-raw.png \
;
do
normal=''${raw%-raw.*}.png
@ -97,49 +136,79 @@ pkgs.writeDashBin "generate-wallpaper" ''
fi
done
# create nightmap-fullsnow
if needs_rebuild nightmap-fullsnow.png; then
convert -size $in_size xc:$nightsnow_color nightmap-fullsnow.png
# remove snow from ice map
if needs_rebuild ice.png ice-raw.jpg; then
convert ice-raw.jpg -fuzz 20% -fill black -opaque white -scale "$in_size" ice.png
fi
# extract daymap-snowmask from daymap-final
if needs_rebuild daymap-snowmask.png daymap.png; then
convert daymap.png -threshold 95% daymap-snowmask.png
if needs_rebuild snow.png snow-raw.jpg; then
convert snow-raw.jpg -fuzz 20% -fill '#DEDEDE' -opaque white -scale "$in_size" snow.png
fi
# extract nightmap-lightmask from nightmap
if needs_rebuild nightmap-lightmask.png nightmap.png; then
convert nightmap.png -threshold 25% nightmap-lightmask.png
# make fire more red
if needs_rebuild fire.png fire-raw.jpg; then
convert fire-raw.jpg -fuzz 20% -fill '#ef840c' -opaque white -scale "$in_size" fire.png
fi
# create layers
make_layer nightmap-snowlayer.png nightmap-fullsnow.png daymap-snowmask.png
make_layer nightmap-lightlayer.png nightmap.png nightmap-lightmask.png
# cut out sun with alpha transparency
if needs_rebuild sun.png sun-raw.jpg; then
convert sun-raw.jpg \
\( +clone -colorspace HSB -fill white -draw "circle 256,256 256,54" -separate -delete 0,1 \) \
-compose copyopacity -composite -crop 512x472+0+20 -scale "100x100" sun.png
fi
# apply layers
flatten nightmap-lightsnowlayer.png \
nightmap-lightlayer.png \
nightmap-snowlayer.png
if needs_rebuild krebs.png krebs-raw.svg; then
inkscape -z -e krebs.png -w 16 -h 16 krebs-raw.svg
fi
flatten nightmap-final.png \
nightmap-lightsnowlayer.png \
nightmap.png
# -- Planets --
for planet in mercury venus mars jupiter saturn uranus neptune; do
if needs_rebuild "$planet".png "$planet"-raw.svg; then
sed -i 's/#000/#FE8019/g' "$planet"-raw.svg
inkscape -z -e "$planet".png -w 40 -h 40 "$planet"-raw.svg
fi
done
# -- Daymap --
# merge with water chlora layer
if needs_rebuild daymap-final.png daymap.png fire.png snow.png ice.png chlora.png; then
convert daymap.png fire.png -compose lighten -composite daymap-1.png
convert daymap-1.png ice.png -compose lighten -composite daymap-2.png
convert daymap-2.png snow.png -compose lighten -composite daymap-3.png
convert daymap-3.png chlora.png -compose lighten -composite daymap-final.png
fi
# -- Nightmap --
if needs_rebuild nightmap-final.png nightmap.png fire.png snow.png ice.png chlora.png; then
convert nightmap.png fire.png -compose lighten -composite nightmap-1.png
convert nightmap-1.png \( -fill black -colorize 70% ice.png \) -compose lighten -composite nightmap-2.png
convert nightmap-2.png \( -fill black -colorize 70% snow.png \) -compose lighten -composite nightmap-3.png
convert nightmap-3.png \( -fill black -colorize 70% chlora.png \) -compose lighten -composite nightmap-final.png
fi
# create marker file from json
if [ -s marker.json ]; then
jq -r 'to_entries[] | @json "\(.value.latitude) \(.value.longitude)"' marker.json > marker_file
jq -r 'to_entries[] | @json "\(.value.latitude) \(.value.longitude) image=krebs.png"' marker.json > marker_file
echo 'position=sun image=sun.png' >> marker_file
echo 'position=moon image=moon.png' >> marker_file
echo 'position=mercury image=mercury.png' >> marker_file
echo 'position=venus image=venus.png' >> marker_file
echo 'position=mars image=mars.png' >> marker_file
echo 'position=jupiter image=jupiter.png' >> marker_file
echo 'position=saturn image=saturn.png' >> marker_file
echo 'position=uranus image=uranus.png' >> marker_file
echo 'position=neptune image=neptune.png' >> marker_file
fi
# make all unmodified files as final
for normal in \
daymap.png \
clouds.png \
;
do
final=''${normal%.png}-final.png
needs_rebuild $final &&
ln $normal $final
done
# generate moon
xplanet -body moon --num_times 1 -origin earth \
--transpng moon.png --geometry 50x50 \
-config ${pkgs.writeText "moon.config" ''
[moon]
shade=10
''}
# rebuild every time to update shadow
xplanet --num_times 1 --geometry $xplanet_out_size \
@ -149,8 +218,9 @@ pkgs.writeDashBin "generate-wallpaper" ''
"Earth"
map=daymap-final.png
night_map=nightmap-final.png
cloud_map=clouds-final.png
cloud_threshold=10
cloud_map=clouds.png
cloud_threshold=1
cloud_gamma=10
shade=15
''}
@ -161,8 +231,9 @@ pkgs.writeDashBin "generate-wallpaper" ''
"Earth"
map=daymap-final.png
night_map=nightmap-final.png
cloud_map=clouds-final.png
cloud_threshold=10
cloud_map=clouds.png
cloud_threshold=1
cloud_gamma=10
marker_file=marker_file
shade=15
''}
@ -178,6 +249,8 @@ pkgs.writeDashBin "generate-wallpaper" ''
convert xplanet-krebs-output.png -crop $out_geometry \
realwallpaper-krebs-tmp.png
mv realwallpaper-krebs-tmp.png realwallpaper-krebs.png
mkdir -p archive
convert realwallpaper-krebs.png archive/"$(date -Is)".jpg
fi
}

View File

@ -31,18 +31,19 @@
};
};
stockholm.file = toString ../.;
stockholm-version.pipe = toString (pkgs.writeDash "${name}-version" ''
set -efu
cd ${lib.escapeShellArg stockholm.file}
V=$(${pkgs.coreutils}/bin/date +%y.%m)
if test -d .git; then
V=$V.git.$(${pkgs.git}/bin/git describe --always --dirty)
case $V in (*-dirty)
V=$V@''${HOSTNAME-$(${pkgs.nettools}/bin/hostname)}
esac
fi
printf %s "$V"
'');
stockholm-version.pipe =
toString (pkgs.writers.writeDash "${name}-version" ''
set -efu
cd ${lib.escapeShellArg stockholm.file}
V=$(${pkgs.coreutils}/bin/date +%y.%m)
if test -d .git; then
V=$V.git.$(${pkgs.git}/bin/git describe --always --dirty)
case $V in (*-dirty)
V=$V@''${HOSTNAME-$(${pkgs.nettools}/bin/hostname)}
esac
fi
printf %s "$V"
'');
};
source ={ test }: lib.evalSource [

View File

@ -1,7 +1,7 @@
{
"url": "https://github.com/NixOS/nixpkgs-channels",
"rev": "100012e55bc2a82fc680cba31a426ad38ead6fab",
"date": "2020-01-12T00:04:23+00:00",
"sha256": "0cvnx852n0krci9hi1rpcldx1kcpmvi5ihf2awvwfayvzp4wic8z",
"rev": "d96bd3394b734487d1c3bfbac0e8f17465e03afe",
"date": "2020-03-19T15:32:34+01:00",
"sha256": "05n27wz5ln9ni5cy5rhjcy612i44gmblkq5m0g827v8pd0nk00da",
"fetchSubmodules": false
}

View File

@ -1,7 +1,7 @@
{
"url": "https://github.com/NixOS/nixpkgs-channels",
"rev": "c49da6435f314e04fc58ca29807221817ac2ac6b",
"date": "2020-02-07T12:52:16+01:00",
"sha256": "17zsqhaf098bvcfarnq0h9601z6smkfd1kz1px6xfg6xqfmr80r7",
"rev": "598a9cbed6348ebda43c6b1a9a3061e0206297e7",
"date": "2020-03-28T03:06:32+01:00",
"sha256": "12m910j2sfhm3a6skw4janxy010gzdxp15bn8v9w7w9hhjzvdw8c",
"fetchSubmodules": false
}

View File

@ -33,4 +33,6 @@
services.logind.lidSwitch = "ignore";
services.logind.lidSwitchDocked = "ignore";
boot.tmpOnTmpfs = true;
}

View File

@ -49,17 +49,17 @@ with import <stockholm/lib>;
];
}
{
krebs.syncthing = {
peers.schasch.addresses = [ "schasch.r:22000" ];
services.syncthing.declarative = {
devices.schasch.addresses = [ "schasch.r:22000" ];
folders = {
the_playlist = {
path = "/home/lass/tmp/the_playlist";
peers = [ "mors" "phone" "prism" "xerxes" ];
devices = [ "mors" "phone" "prism" "xerxes" ];
};
free_music = {
id = "mu9mn-zgvsw";
path = "/home/lass/tmp/free_music";
peers = [ "mors" "schasch" ];
devices = [ "mors" "schasch" ];
};
};
};

View File

@ -338,30 +338,36 @@ with import <stockholm/lib>;
localAddress = "10.233.2.14";
};
services.nginx.virtualHosts."lassul.us".locations."^~ /flix/".extraConfig = ''
if ($scheme != "https") {
rewrite ^ https://$host$request_uri permanent;
}
auth_basic "Restricted Content";
auth_basic_user_file ${pkgs.writeText "flix-user-pass" ''
krebs:$apr1$1Fwt/4T0$YwcUn3OBmtmsGiEPlYWyq0
''};
proxy_pass http://10.233.2.14:80/;
proxy_set_header Accept-Encoding "";
sub_filter "https://lassul.us/" "https://lassul.us/flix/";
sub_filter_once off;
'';
services.nginx.virtualHosts."lassul.us".locations."^~ /transmission".extraConfig = ''
if ($scheme != "https") {
rewrite ^ https://$host$request_uri permanent;
}
auth_basic "Restricted Content";
auth_basic_user_file ${pkgs.writeText "transmission-user-pass" ''
krebs:$apr1$1Fwt/4T0$YwcUn3OBmtmsGiEPlYWyq0
''};
proxy_pass_header X-Transmission-Session-Id;
proxy_pass http://10.233.2.14:9091;
'';
services.nginx.virtualHosts."lassul.us" = {
locations."^~ /flix/".extraConfig = ''
if ($scheme != "https") {
rewrite ^ https://$host$request_uri permanent;
}
auth_basic "Restricted Content";
auth_basic_user_file ${pkgs.writeText "flix-user-pass" ''
krebs:$apr1$1Fwt/4T0$YwcUn3OBmtmsGiEPlYWyq0
''};
proxy_pass http://10.233.2.14:80/;
proxy_set_header Accept-Encoding "";
sub_filter "https://lassul.us/" "https://lassul.us/flix/";
sub_filter_once off;
'';
locations."^~ /chatty/".extraConfig = ''
rewrite ^ https://$host/flix/$request_uri permanent;
'';
#locations."^~ /transmission".return = "301 https://$host/transmission/web/";
locations."^~ /transmission/".extraConfig = ''
if ($scheme != "https") {
rewrite ^ https://$host$request_uri permanent;
}
auth_basic "Restricted Content";
auth_basic_user_file ${pkgs.writeText "transmission-user-pass" ''
krebs:$apr1$1Fwt/4T0$YwcUn3OBmtmsGiEPlYWyq0
''};
proxy_pass_header X-Transmission-Session-Id;
proxy_pass http://10.233.2.14:9091;
'';
};
users.groups.download = {};
users.users = {

View File

@ -41,11 +41,11 @@
displayManager.lightdm.autoLogin.user = "lass";
};
krebs.syncthing = {
services.syncthing.declarative = {
folders = {
the_playlist = {
path = "/home/lass/tmp/the_playlist";
peers = [ "mors" "phone" "prism" "xerxes" ];
devices = [ "mors" "phone" "prism" "xerxes" ];
};
};
};

View File

@ -54,12 +54,107 @@ with import <stockholm/lib>;
root = "/var/download/finished";
extraConfig = ''
fancyindex on;
dav_methods PUT DELETE MKCOL COPY MOVE;
fancyindex_footer "/fancy.html";
include ${pkgs.nginx}/conf/mime.types;
include ${pkgs.writeText "extrMime" ''
types {
video/webm mkv;
}
''};
create_full_put_path on;
dav_access all:r;
'';
};
locations."/chatty" = {
proxyPass = "http://localhost:3000";
extraConfig = ''
rewrite /chatty/(.*) /$1 break;
proxy_set_header Host $host;
'';
};
locations."= /fancy.html".extraConfig = ''
alias ${pkgs.writeText "nginx_footer" ''
<div id="mydiv">
<!-- Include a header DIV with the same name as the draggable DIV, followed by "header" -->
<div id="mydivheader">Click here to move</div>
<iframe src="/chatty/index.html"></iframe>
</div>
<style>
#mydiv {
position: absolute;
z-index: 9;
background-color: #f1f1f1;
border: 1px solid #d3d3d3;
text-align: center;
}
#mydivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
</style>
<script>
// Make the DIV element draggable:
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
// if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
</script>
''};
'';
};
};
systemd.services.bruellwuerfel = {
wantedBy = [ "multi-user.target" ];
environment = {
IRC_CHANNEL = "#flix";
IRC_NICK = "bruelli";
IRC_SERVER = "irc.r";
IRC_HISTORY_FILE = "/tmp/bruelli.history";
};
serviceConfig = {
ExecStart = "${pkgs.bruellwuerfel}/bin/bruellwuerfel";
};
};

View File

@ -102,6 +102,14 @@
"microsoft@lassul.us"
"stickers@lassul.us"
"nextbike@lassul.us"
"mytello@lassul.us"
"camp@lassul.us"
"urlwatch@lassul.us"
"lidl@lassul.us"
"geizhals@lassul.us"
"auschein@lassul.us"
"tleech@lassul.us"
"durstexpress@lassul.us"
];
in {

View File

@ -65,7 +65,7 @@ in {
createHome = true;
useDefaultShell = true;
packages = with pkgs; [
minecraft
# minecraft
steam-run
scummvm
dolphinEmu

View File

@ -20,7 +20,7 @@ with import <stockholm/lib>;
}
];
krebs.syncthing.folders."/var/lib/sync-containers".peers = [ "icarus" "skynet" "littleT" "shodan" ];
services.syncthing.declarative.folders."/var/lib/sync-containers".devices = [ "icarus" "skynet" "littleT" "shodan" ];
krebs.permown."/var/lib/sync-containers" = {
owner = "root";
group = "syncthing";

View File

@ -2,11 +2,85 @@
let
download_subs = pkgs.writers.writePython3 "download_sub" {
libraries = [ pkgs.python3Packages.subliminal ];
} ''
from subliminal import download_best_subtitles, scan_video
from babelfish import Language
import sys
video_filename = sys.argv[1]
vid = scan_video(video_filename)
try:
sub = download_best_subtitles([vid], {Language('eng')})[vid][0]
filename = '/tmp/' + vid.title + '.srt'
with open(filename, 'wb+') as file:
file.write(sub.content)
print(filename)
except: # noqa
print("/dev/null")
'';
autosub = pkgs.writeText "autosub.lua" ''
-- Requires Subliminal version 1.0 or newer
-- Make sure to specify your system's Subliminal location below:
local utils = require 'mp.utils'
-- Log function: log to both terminal and mpv OSD (On-Screen Display)
function log(string, secs)
secs = secs or 2 -- secs defaults to 2 when the secs parameter is absent
mp.msg.warn(string) -- This logs to the terminal
mp.osd_message(string, secs) -- This logs to mpv screen
end
function download()
log('Searching subtitles ...', 10)
table = { args = {"${download_subs}", mp.get_property('path')} }
result = utils.subprocess(table)
if result.error == nil then
-- remove trailing newline from subtitle filename
filename = string.gsub(result.stdout, "\n", "")
log(filename)
mp.commandv('sub_add', filename)
log('Subtitles ready!')
else
log('Subtitles failed downloading')
end
end
-- Control function: only download if necessary
function control_download()
duration = tonumber(mp.get_property('duration'))
if duration < 900 then
mp.msg.warn('Video is less than 15 minutes\n', '=> NOT downloading any subtitles')
return
end
-- There does not seem to be any documentation for the 'sub' property,
-- but it works on both internally encoded as well as external subtitle files!
-- -> sub = '1' when subtitles are present
-- -> sub = 'no' when subtitles are not present
-- -> sub = 'auto' when called before the 'file-loaded' event is triggered
sub = mp.get_property('sub')
if sub == '1' then
mp.msg.warn('Sub track is already present\n', '=> NOT downloading other subtitles')
return
end
mp.msg.warn('No sub track was detected\n', '=> Proceeding to download subtitles:')
download()
end
mp.add_key_binding('S', "download_subs", download)
'';
mpv = pkgs.symlinkJoin {
name = "mpv";
paths = [
(pkgs.writeDashBin "mpv" ''
exec ${pkgs.mpv}/bin/mpv --no-config "$@"
exec ${pkgs.mpv}/bin/mpv --no-config --script=${autosub} "$@"
'')
pkgs.mpv
];

View File

@ -9,13 +9,28 @@ let
admin-password = import <secrets/icecast-admin-pw>;
source-password = import <secrets/icecast-source-pw>;
music_dir = "/home/radio/music";
add_random = pkgs.writeDashBin "add_random" ''
${pkgs.mpc_cli}/bin/mpc add "$(${pkgs.mpc_cli}/bin/mpc ls the_playlist/music | grep '\.ogg$' | shuf -n1)"
'';
skip_track = pkgs.writeDashBin "skip_track" ''
set -eu
${add_random}/bin/add_random
echo skipping: "$(${print_current}/bin/print_current)"
music_dir=${escapeShellArg music_dir}
current_track=$(${pkgs.mpc_cli}/bin/mpc current -f %file%)
track_infos=$(${print_current}/bin/print_current)
skip_count=$(${pkgs.attr}/bin/getfattr -n user.skip_count --only-values "$music_dir"/"$current_track" || echo 0)
if [ "$skip_count" -gt 2 ]; then
mv "$music_dir"/"$current_track" "$music_dir"/.graveyard/
echo killing: "$track_infos"
else
skip_count=$((skip_count+1))
${pkgs.attr}/bin/setfattr -n user.skip_count -v "$skip_count" "$music_dir"/"$current_track"
echo skipping: "$track_infos" skip_count: "$skip_count"
fi
${pkgs.mpc_cli}/bin/mpc -q next
'';
@ -57,7 +72,7 @@ in {
services.mpd = {
enable = true;
group = "radio";
musicDirectory = "/home/radio/music";
musicDirectory = "${music_dir}";
extraConfig = ''
log_level "default"
auto_update "yes"
@ -178,11 +193,15 @@ in {
};
};
# allow reaktor2 to modify files
systemd.services."reaktor2-the_playlist".serviceConfig.DynamicUser = mkForce false;
krebs.reaktor2.the_playlist = {
hostname = "irc.freenode.org";
port = "6697";
useTLS = true;
nick = "the_playlist";
username = "radio";
plugins = [
{
plugin = "register";
@ -199,8 +218,8 @@ in {
workdir = config.krebs.reaktor2.the_playlist.stateDir;
hooks.PRIVMSG = [
{
#activate = "match";
pattern = "^\\s*([0-9A-Za-z._][0-9A-Za-z._-]*)(?:\\s+(.*\\S))?\\s*$";
activate = "match";
pattern = "^(?:.*\\s)?\\s*the_playlist:\\s*([0-9A-Za-z._][0-9A-Za-z._-]*)(?:\\s+(.*\\S))?\\s*$";
command = 1;
arguments = [2];
commands = {
@ -258,9 +277,9 @@ in {
alias ${html};
'';
};
krebs.syncthing.folders."the_playlist" = {
services.syncthing.declarative.folders."the_playlist" = {
path = "/home/radio/music/the_playlist";
peers = [ "mors" "phone" "prism" "xerxes" ];
devices = [ "mors" "phone" "prism" "xerxes" ];
};
krebs.permown."/home/radio/music/the_playlist" = {
owner = "radio";

View File

@ -1,7 +1,7 @@
{
krebs.syncthing.folders.decsync = {
services.syncthing.declarative.folders.decsync = {
path = "/home/lass/decsync";
peers = [ "mors" "blue" "green" "phone" ];
devices = [ "mors" "blue" "green" "phone" ];
};
krebs.permown."/home/lass/decsync" = {
owner = "lass";

View File

@ -1,5 +1,5 @@
{
krebs.syncthing.folders."/home/lass/.weechat".peers = [ "blue" "green" "mors" ];
services.syncthing.declarative.folders."/home/lass/.weechat".devices = [ "blue" "green" "mors" ];
krebs.permown."/home/lass/.weechat" = {
owner = "lass";
group = "syncthing";

View File

@ -7,18 +7,20 @@ in {
enable = true;
group = "syncthing";
configDir = "/var/lib/syncthing";
declarative = {
key = toString <secrets/syncthing.key>;
cert = toString <secrets/syncthing.cert>;
devices = mk_peers all_peers;
folders."/home/lass/sync" = {
devices = attrNames (filterAttrs (n: v: n != "phone") own_peers);
# ignorePerms = false;
};
};
};
krebs.iptables.tables.filter.INPUT.rules = [
{ predicate = "-p tcp --dport 22000"; target = "ACCEPT";}
{ predicate = "-p udp --dport 21027"; target = "ACCEPT";}
];
krebs.syncthing = {
enable = true;
cert = toString <secrets/syncthing.cert>;
key = toString <secrets/syncthing.key>;
peers = mk_peers all_peers;
folders."/home/lass/sync".peers = attrNames (filterAttrs (n: v: n != "phone") own_peers);
};
system.activationScripts.syncthing-home = ''
${pkgs.coreutils}/bin/chmod a+x /home/lass

View File

@ -270,14 +270,14 @@ in {
};
boot.kernel.sysctl."fs.inotify.max_user_watches" = "1048576";
krebs.syncthing.folders = {
services.syncthing.declarative.folders = {
domsen-backups = {
path = "/backups/domsen";
peers = [ "domsen-backup" ];
devices = [ "domsen-backup" ];
};
domsen-backup-srv-http = {
path = "/srv/http";
peers = [ "domsen-backup" ];
devices = [ "domsen-backup" ];
};
};

View File

@ -0,0 +1,26 @@
{ yarn2nix-moretea, fetchFromGitHub, nodePackages, nodejs }: let
#src = ~/src/bruellwuerfel;
src = fetchFromGitHub {
owner = "krebs";
repo = "bruellwuerfel";
rev = "57e20e630f732ce4e15b495ec5f9bf72a121b959";
sha256 = "08zwwl24sq21r497a03lqpy2x10az8frrsh6d38xm92snd1yf85b";
};
in yarn2nix-moretea.mkYarnModules rec {
pname = "bruellwuerfel";
version = "1.0";
name = "${pname}-${version}";
packageJSON = "${src}/package.json";
yarnLock = "${src}/yarn.lock";
postBuild = ''
cp -r ${src}/{src,tsconfig.json} $out/
cd $out
${nodePackages.typescript}/bin/tsc || :
mkdir -p $out/bin
echo '#!/bin/sh' > $out/bin/bruellwuerfel
echo "export NODE_PATH=$out/dist" >> $out/bin/bruellwuerfel
echo "${nodejs}/bin/node $out/dist/index.js" >> $out/bin/bruellwuerfel
chmod +x $out/bin/bruellwuerfel
'';
}

View File

@ -32,14 +32,24 @@ pkgs.writeDashBin "fzfmenu" ''
done
INPUT=$(${pkgs.coreutils}/bin/cat)
OUTPUT="$(${pkgs.coreutils}/bin/mktemp)"
${pkgs.rxvt_unicode}/bin/urxvt \
-name fzfmenu -title fzfmenu \
-e ${pkgs.dash}/bin/dash -c \
"echo \"$INPUT\" | ${pkgs.fzf}/bin/fzf \
--history=/dev/null \
--print-query \
--prompt=\"$PROMPT\" \
> \"$OUTPUT\"" 2>/dev/null
if [ -z ''${TERM+x} ]; then #check if we can print fzf in the shell
${pkgs.rxvt_unicode}/bin/urxvtc \
-name fzfmenu -title fzfmenu \
-e ${pkgs.dash}/bin/dash -c \
"echo \"$INPUT\" | ${pkgs.fzf}/bin/fzf \
--history=/dev/null \
--print-query \
--prompt=\"$PROMPT\" \
--reverse \
> \"$OUTPUT\"" 2>/dev/null
else
echo "$INPUT" | ${pkgs.fzf}/bin/fzf \
--history=/dev/null \
--print-query \
--prompt="$PROMPT" \
--reverse \
> "$OUTPUT"
fi
${pkgs.coreutils}/bin/tail -1 "$OUTPUT"
${pkgs.coreutils}/bin/rm "$OUTPUT"
''

View File

@ -21,11 +21,12 @@ in {
];
};
}
<stockholm/makefu/2configs/nur.nix>
<stockholm/makefu/2configs/support-nixos.nix>
<stockholm/makefu/2configs/home-manager>
<stockholm/makefu/2configs/home-manager/cli.nix>
# <stockholm/makefu/2configs/stats/client.nix>
<stockholm/makefu/2configs/stats/netdata-server.nix>
# <stockholm/makefu/2configs/stats/netdata-server.nix>
<stockholm/makefu/2configs/headless.nix>
<stockholm/makefu/2configs/smart-monitor.nix>
@ -89,8 +90,8 @@ in {
# services
# <stockholm/makefu/2configs/sabnzbd.nix>
<stockholm/makefu/2configs/mail/mail.euer.nix>
{ krebs.exim.enable = mkForce false; }
# <stockholm/makefu/2configs/mail/mail.euer.nix>
{ krebs.exim.enable = mkDefault true; }
# sharing
<stockholm/makefu/2configs/share/gum.nix>
@ -119,7 +120,7 @@ in {
<stockholm/makefu/2configs/urlwatch>
# Removed until move: avoid letsencrypt ban
### Web
#<stockholm/makefu/2configs/nginx/share-download.nix>
<stockholm/makefu/2configs/nginx/dl.euer.krebsco.de.nix>
#<stockholm/makefu/2configs/nginx/euer.test.nix>
<stockholm/makefu/2configs/nginx/euer.mon.nix>
<stockholm/makefu/2configs/nginx/euer.wiki.nix>
@ -131,10 +132,14 @@ in {
# <stockholm/makefu/2configs/nginx/gold.krebsco.de.nix>
# <stockholm/makefu/2configs/nginx/iso.euer.nix>
<stockholm/makefu/2configs/deployment/photostore.krebsco.de.nix>
# <stockholm/makefu/2configs/deployment/photostore.krebsco.de.nix>
<stockholm/makefu/2configs/deployment/graphs.nix>
<stockholm/makefu/2configs/deployment/owncloud.nix>
<stockholm/makefu/2configs/deployment/board.euer.krebsco.de.nix>
<stockholm/makefu/2configs/deployment/rss.euer.krebsco.de.nix>
<stockholm/makefu/2configs/deployment/boot-euer.nix>
<stockholm/makefu/2configs/deployment/gecloudpad>
<stockholm/makefu/2configs/deployment/docker/archiveteam-warrior.nix>
<stockholm/makefu/2configs/shiori.nix>
<stockholm/makefu/2configs/bgt/download.binaergewitter.de.nix>
@ -171,7 +176,8 @@ in {
services.nginx.virtualHosts."cgit.euer.krebsco.de" = {
forceSSL = true;
enableACME = true;
locations."/".proxyPass = "http://cgit.gum.r";
locations."/".proxyPass = "http://localhost/";
locations."/".extraConfig = ''proxy_set_header Host cgit;'';
};
krebs.build.host = config.krebs.hosts.gum;

View File

@ -57,7 +57,7 @@ in {
<stockholm/makefu/2configs/stats/telegraf>
# <stockholm/makefu/2configs/stats/telegraf/europastats.nix>
<stockholm/makefu/2configs/stats/telegraf/hamstats.nix>
<stockholm/makefu/2configs/stats/arafetch.nix>
# <stockholm/makefu/2configs/stats/arafetch.nix>
# services
{
@ -71,14 +71,9 @@ in {
<stockholm/makefu/2configs/virtualisation/docker.nix>
<stockholm/makefu/2configs/bluetooth-mpd.nix>
{
# Risikoübernahme
nixpkgs.config.permittedInsecurePackages = [
"homeassistant-0.77.2"
];
}
<stockholm/makefu/2configs/homeautomation>
<stockholm/makefu/2configs/homeautomation/google-muell.nix>
<stockholm/makefu/2configs/ham>
<stockholm/makefu/2configs/ham/google-muell.nix>
<stockholm/makefu/2configs/ham/zigbee2mqtt>
{
makefu.ps3netsrv = {
enable = true;
@ -90,7 +85,6 @@ in {
makefu.mpd.musicDirectory = "/media/cryptX/music";
}
# security
<stockholm/makefu/2configs/sshd-totp.nix>
# <stockholm/makefu/2configs/logging/central-logging-client.nix>
@ -120,7 +114,7 @@ in {
gid = (import <stockholm/lib>).genid "share";
members = [ "makefu" "misa" ];
};
networking.firewall.trustedInterfaces = [ primaryInterface ];
networking.firewall.trustedInterfaces = [ primaryInterface "docker0" ];
@ -141,18 +135,18 @@ in {
sed-plugin
random-emoji ];
};
krebs.Reaktor.reaktor-bgt = {
nickname = "Reaktor|bgt";
workdir = "/var/lib/Reaktor/bgt";
channels = [ "#binaergewitter" ];
plugins = with pkgs.ReaktorPlugins;
[ titlebot
# stockholm-issue
nixos-version
shack-correct
sed-plugin
random-emoji ];
};
#krebs.Reaktor.reaktor-bgt = {
# nickname = "Reaktor|bgt";
# workdir = "/var/lib/Reaktor/bgt";
# channels = [ "#binaergewitter" ];
# plugins = with pkgs.ReaktorPlugins;
# [ titlebot
# # stockholm-issue
# nixos-version
# shack-correct
# sed-plugin
# random-emoji ];
#};
krebs.build.host = config.krebs.hosts.omo;
}

View File

@ -26,9 +26,10 @@ let
# |_______|
# cryptDisk0 = byid "ata-ST2000DM001-1CH164_Z240XTT6";
cryptDisk0 = byid "ata-ST8000DM004-2CX188_ZCT01PLV";
cryptDisk1 = byid "ata-TP02000GB_TPW151006050068";
cryptDisk2 = byid "ata-ST4000DM000-1F2168_Z303HVSG";
cryptDisk1 = byid "ata-WDC_WD80EZAZ-11TDBA0_7SJPVLYW";
cryptDisk3 = byid "ata-ST8000DM004-2CX188_ZCT01SG4";
cryptDisk2 = byid "ata-WDC_WD80EZAZ-11TDBA0_7SJPWT5W";
# cryptDisk3 = byid "ata-WDC_WD20EARS-00MVWB0_WD-WMAZA1786907";
# all physical disks
@ -48,8 +49,8 @@ in {
makefu.snapraid = {
enable = true;
disks = map toMapper [ 0 2 3 ];
parity = toMapper 1;
disks = map toMapper [ 0 1 3 ];
parity = toMapper 2; # find -name PARITY_PARTITION
};
fileSystems = let
cryptMount = name:
@ -102,6 +103,8 @@ in {
"firewire_ohci"
"usb_storage"
"usbhid"
"raid456"
"megaraid_sas"
];
kernelModules = [ "kvm-intel" ];

View File

@ -1,4 +1,5 @@
{
name="omo";
torrent = true;
unstable = true;
}

View File

@ -58,7 +58,7 @@
# Krebs
<stockholm/makefu/2configs/tinc/retiolum.nix>
<stockholm/makefu/2configs/share/gum-client.nix>
# <stockholm/makefu/2configs/share/gum-client.nix>
# <stockholm/makefu/2configs/share/temp-share-samba.nix>
@ -103,6 +103,7 @@
# <stockholm/makefu/2configs/hw/malduino_elite.nix>
<stockholm/makefu/2configs/hw/switch.nix>
# <stockholm/makefu/2configs/hw/rad1o.nix>
<stockholm/makefu/2configs/hw/cc2531.nix>
<stockholm/makefu/2configs/hw/smartcard.nix>
<stockholm/makefu/2configs/hw/upower.nix>
@ -142,7 +143,6 @@
];
};
}
];
makefu.server.primary-itf = "wlp3s0";

View File

@ -0,0 +1,20 @@
[
{
alias = "Daily news for Felix";
trigger = {
platform = "time";
at = "07:35:00";
};
action =
[
{
service = "notify.telegrambot";
data_template = {
title = "Daily News";
# TODO
message = "";
};
}
];
}
]

View File

@ -0,0 +1,4 @@
# heiss
Lieber Freund, was für ein Sommer! Ich denke Sie mir im Zimmer sitzend, mehr Omelette als Mensch.
Sommer ist die Zeit, in der es zu heiß ist, um das zu tun, wozu es im Winter zu kalt war.

View File

@ -66,9 +66,6 @@ in [
language = "de";
};
}
{ service = "notify.matrix_notify";
data_template.message = "Schlechte Luft Alarm seit ${toString long_threshold} Minuten ({{states.sensor.air_quality.state_with_unit}})!";
}
];
}
]

View File

@ -0,0 +1,26 @@
let
cam = name: still_image_url:
{
inherit name still_image_url;
platform = "generic";
};
in [
( cam "Max-Eyth-See" https://www.wav-stuttgart.de/webcam/_/webcam1.jpg )
( cam "Wilhelma" http://webcam.wilhelma.de/webcam02/webcam02.jpg )
( cam "Marktplatz" https://webcam.stuttgart.de/wcam007/current.jpg )
( cam "Schoch Areal" https://webcam.stuttgart.de/wcam004/current.jpg )
( cam "Leuze" https://webcam.stuttgart.de/wcam005/current.jpg )
( cam "Straße Wilhelma" https://webcam.stuttgart.de/wcam006/current.jpg )
( cam "Fernsehturm 1" http://webcam.fernsehturmstuttgart.com/current.jpg )
( cam "Fernsehturm 2" http://webcam.fernsehturmstuttgart.com/current2.jpg )
( cam "Feuerbach Lemberg" http://www.regio7.de/handy/current.jpg )
( cam "Flughafen Stuttgart 1" http://webcam.flughafen-stuttgart.de/Flughafen_Stuttgart_Webcam2.jpg )
( cam "Flughafen Stuttgart 2" http://webcam.flughafen-stuttgart.de/Flughafen_Stuttgart_Webcam5.jpg )
( cam "Flughafen Stuttgart 3" http://webcam.flughafen-stuttgart.de/Flughafen_Stuttgart_Webcam7.jpg )
( cam "S21 1" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Turm-03/s21-turm03.jpg )
( cam "S21 2" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Turm-02/s21-turm-02.jpg )
( cam "S21 3" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Turm-01/s21-turm-01.jpg )
( cam "S21 4" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Jaegerstrasse-Nordkopf/s21-jaegerstrassse-nordkopf.jpg )
( cam "S21 5" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Bahndirektion-Nord/S21-Bundesbahndirektion-Nord.jpg )
]

View File

@ -11,6 +11,7 @@ in {
imports = [
./ota.nix
./comic-updater.nix
./puppy-proxy.nix
];
networking.firewall.allowedTCPPorts = [ 8123 ];
state = [ "/var/lib/hass/known_devices.yaml" ];
@ -33,13 +34,14 @@ in {
'';
})).override {
extraPackages = ps: with ps; [
pkgs.pico2wave
pkgs.picotts
python-forecastio jsonrpc-async jsonrpc-websocket mpd2
(callPackage ./deps/openwrt-luci-rpc.nix { })
];
};
autoExtraComponents = true;
config = {
discovery = {};
homeassistant = {
name = "Bureautomation";
time_zone = "Europe/Berlin";
@ -72,6 +74,8 @@ in {
};
matrix = matrix.matrix;
mqtt = {
discovery = true;
discovery_prefix = "homeassistant";
broker = "localhost";
port = 1883;
client_id = "home-assistant";
@ -124,7 +128,7 @@ in {
frosch.script
ten_hours.script
mittagessen.script
standup.script
# standup.script
];
binary_sensor =
(import ./binary_sensor/buttons.nix)
@ -145,7 +149,8 @@ in {
camera =
(import ./camera/verkehrskamera.nix)
++ (import ./camera/comic.nix);
++ (import ./camera/comic.nix)
++ (import ./camera/stuttgart.nix);
person =
(import ./person/team.nix );
@ -198,9 +203,10 @@ in {
"switch.blitzdings"
"switch.fernseher"
"switch.feuer"
"switch.frosch_blasen"
"light.status_felix"
"light.status_daniel"
"light.buslicht"
# "light.status_daniel"
# "light.buslicht"
];
team = [
"person.thorsten"
@ -212,6 +218,7 @@ in {
"person.thierry"
"person.frank"
"person.emeka"
"person.tancrede"
#"device_tracker.felix_phone"
#"device_tracker.ecki_tablet"
#"device_tracker.daniel_phone"
@ -228,6 +235,7 @@ in {
"camera.Baumarkt"
"camera.Autobahn_Heilbronn"
"camera.Autobahn_Singen"
"camera.puppies"
"camera.poorly_drawn_lines"
];
nachtlicht = [
@ -264,7 +272,6 @@ in {
outside = [
# "sensor.ditzingen_pm10"
# "sensor.ditzingen_pm25"
"sensor.dark_sky_icon"
"sensor.dark_sky_temperature"
"sensor.dark_sky_humidity"
"sensor.dark_sky_uv_index"
@ -282,7 +289,7 @@ in {
++ (import ./automation/hass-restart.nix)
++ ten_hours.automation
++ matrix.automation
++ standup.automation
# ++ standup.automation
++ frosch.automation
++ mittagessen.automation;
device_tracker = (import ./device_tracker/openwrt.nix );

View File

@ -0,0 +1,38 @@
{ lib
, buildPythonPackage
, fetchPypi
# propagatedBuildInputs
, aiohttp
# buildInputs
, pytest
, pytest-asyncio
}:
buildPythonPackage rec {
pname = "aresponses";
version = "1.1.1";
src = fetchPypi {
inherit pname version;
sha256 = "d1d6ef52b9a97142d106688cf9b112602ef3dc66f6368de8f91f47241d8cfc9c";
};
propagatedBuildInputs = [
aiohttp
];
buildInputs = [
pytest
pytest-asyncio
];
# tests only distributed via git repository, not pypi
doCheck = false;
meta = with lib; {
description = "Asyncio testing server";
homepage = "https://github.com/circleup/aresponses";
license = licenses.mit;
maintainers = [ maintainers.makefu ];
};
}

View File

@ -2,6 +2,8 @@
let
persons = [ "frank" "daniel" "thorsten" "carsten" "ecki" "felix"
"thierry" # tjeri
"emeka"
"tancrede"
];
random_zu_lange = name: ''{{ [
"Du musst jetzt endlich nach Hause gehen ${name}!",
@ -20,6 +22,7 @@ let
random_announce = name: ''{{ [
"${name} is in da House",
"Ahoi ${name}",
"Hallöchen Popöchen ${name}",
"Moinsen ${name}",
"Moin Moin ${name}",
"Palim, Palim ${name}",
@ -55,7 +58,7 @@ let
"Und es startet für ${name} wieder ein Tag im Paradies",
"Lieber ${name}, Markus Keck hat dich bereits drei mal Versucht anzurufen!",
"Trotz schwerer Männergrippe ist ${name} heute im Büro erschienen.",
"${name} kenne keine Parteien mehr, ${name} kenne nur noch Arbeitsplätze",
"${name} kennt keine Parteien mehr, ${name} kennt nur noch Arbeitsplätze",
"${name}, Frage nicht, was dein Arbeitsplatz für dich tun kann. Frage, was du für deinen Arbeitsplatz tun kannst",
"${name} läuft bis in den Jemen - für sein Unternehmen. ${name} schwimmt bis nach Birma - für seine Firma",
"Der Cyberian ${name} ist gekommen um die Bahnwelt vor Cyber-Angriffen zu schützen",
@ -121,7 +124,6 @@ let
{ alias = "start ${name} 10h";
trigger = {
platform = "state";
# TODO: ecki
entity_id = [ "person.${name}"];
from = "not_home";
to = "home";
@ -129,13 +131,11 @@ let
condition = {
condition = "and";
conditions = [
{
condition = "state";
{ condition = "state";
entity_id = "timer.${name}_10h";
state = "idle";
}
{
condition = "time";
{ condition = "time";
after = "06:00:00";
before = "12:00:00";
}
@ -146,8 +146,8 @@ let
entity_id = [ "timer.${name}_10h" ] ;
}
{ service = "homeassistant.turn_on";
entity_id = [
# "switch.fernseher"
entity_id =
[ "switch.fernseher"
"script.blitz_10s"
"script.announce_${name}"
];
@ -155,30 +155,45 @@ let
];
}
{ alias = "pommes announce ${name}";
trigger =
{ platform = "event";
event_type = "timer.started";
event_data.entity_id = "timer.${name}_10h";
};
condition =
{ condition = "state";
entity_id = "binary_sensor.pommes";
state = "on";
};
action =
{ service = "homeassistant.turn_on";
entity_id = "script.blasen_10s" ;
};
}
{ alias = "Zu lange ${name}!";
trigger =
{
platform = "event";
{ platform = "event";
event_type = "timer.finished";
event_data.entity_id = "timer.${name}_10h";
};
condition =
{
condition = "state";
{ condition = "state";
entity_id = "person.${name}";
state = "home";
};
action =
[
{ service = "homeassistant.turn_on";
entity_id = [
"script.blitz_10s"
"script.zu_lange_${name}"
];
}
];
{ service = "homeassistant.turn_on";
entity_id = [
"script.blitz_10s"
"script.zu_lange_${name}"
];
};
}
];
in
@ -187,7 +202,7 @@ in
(map tmr_10h persons);
automation = (lib.flatten (map automation_10h persons));
script = lib.fold lib.recursiveUpdate {} (
(map (p: announce_user p) persons) ++
(map (p: zu_lange_user p) persons)
(map announce_user persons) ++
(map zu_lange_user persons)
);
}

View File

@ -3,9 +3,9 @@ let
random_daily_text = ''{{ [
"Es ist so weit, es ist Standup Zeit!",
"Zehn Uhr Fünfunddreissig ist genau die richtige Zeit für ein Standup!",
"Hat jeder seine Hausaufgaben gemacht? Bitte einmal aufstehen und den Zettel nach rechts geben",
"Hat jeder seine zum Standup seine Hausaufgaben gemacht. Bitte einmal aufstehen und den Zettel nach rechts geben",
"Aufstehen zum Appell, es wird die Anwesenheit kontrolliert!",
"Hallo Kinder, wisst ihr welche Zeit es ist??? ... Genau! ... Standup Zeit!",
"Hallo Kinder, wisst ihr welche Zeit es ist ... Genau ... Standup Zeit!",
"Morgens, halb elf in Deutschland - das Standupchen" ] | random }}'';
in {

View File

@ -1,5 +1,6 @@
{ lib }:
# needs: binary_sensor.pommes
# notify.matrix_notify
let
random_pommes = '' {{ [
"Nur ein Pommes Tag ist ein guter Tag",
@ -51,7 +52,7 @@ in {
{ alias = "Pommeszeit";
trigger = {
platform = "time";
at = "12:15:00";
at = "11:00:00";
};
condition = {
condition = "state";
@ -89,6 +90,9 @@ in {
language = "de";
};
}
{ service = "notify.matrix_notify";
data_template.message = random_pommes;
}
];
};
};

View File

@ -22,9 +22,9 @@ let
"Heute bei Aramark: Rezepte aus Ländern, von denen Ihr noch nie gehört habt, Deutsch zubereitet",
"Heute bei Aramark im Angebot: Scheiss mit Reis oder Reste von Freitag",
"MHHHH es ist wieder mal so weit, lecker Bayerisch Kraut mit asiatischen Nudeln",
"Es ist 12 Uhr 30 und Heute gibt es Pommes - vielleicht",
"Heute gibt es Pommes - leider nicht einzeln zu verkaufen, da die Schälchen alle sind",
"Heute gibt es Pommes - verarscht! Natürlich gibt es nur salzlosen Reis, oder salzlose Nudeln.",
"Es ist 12 Uhr 30 und Heute gibt es nur Pommes, wenn der Pommesfrosch Blasen gespuckt hat.",
"Heute gibt es Pommes leider nicht einzeln zu verkaufen, da die Schälchen alle sind",
"Heute gibt es Pommes, verarscht! Natürlich gibt es nur salzlosen Reis, oder salzlose Nudeln.",
"Heute auf dem Speiseplan: Sushi vom Vortag",
"Aramark Kantinenessen: Der Hunger treibt es rein, der Geiz hält es drin.",
"Das Essen in der Snackeria sieht heute wie die bessere Alternative aus",

View File

@ -50,16 +50,23 @@
"device_tracker.emeka_phone"
];
}
#{ name = "Sabine";
# id = 9;
# device_trackers = [
# "device_tracker.sabine_phone"
# ];
#}
{ name = "Sabine";
id = 9;
device_trackers = [
"device_tracker.sabine_phone"
];
}
{ name = "Tobias";
id = 10;
device_trackers = [
"device_tracker.tobias_phone"
];
}
{ name = "Tancrede";
id = 11;
device_trackers = [
"device_tracker.tancrede_phone"
"device_tracker.tancrede_laptop"
];
}
]

View File

@ -0,0 +1,5 @@
{ pkgs, ... }:
# streamlink 'https://www.ustream.tv/channel/maximilian-schnauzers-cam4' worst --player-external-http --player-external-http-port 15321 --player-passthrough rtsp --retry-streams 60
{
environment.systemPackages = [ pkgs.liveproxy ];
}

View File

@ -36,6 +36,18 @@ in {
count = 1;
alias = "blitz for 10 seconds";
});
blasen_10s = (flash_entity {
entity = "switch.frosch_blasen";
delay = 10000;
count = 1;
alias = "blasen for 10 seconds";
});
blasen_30s = (flash_entity {
entity = "switch.frosch_blasen";
delay = 30000;
count = 1;
alias = "blasen for 30 seconds";
});
schlechteluft = (flash_entity {
entity = "switch.bauarbeiterlampe";
alias = "Schlechte Luft Lampe 5 secs";

View File

@ -0,0 +1,4 @@
[
{ stream_source = "http://127.0.0.1:53422/base64/c3RyZWFtbGluayBodHRwczovL3d3dy51c3RyZWFtLnR2L2NoYW5uZWwvbWF4aW1pbGlhbi1zY2huYXV6ZXJzLWNhbTIgd29yc3Q=/";
}
]

View File

@ -28,6 +28,7 @@ with import <stockholm/lib>;
openssh.authorizedKeys.keys = [ config.krebs.users.makefu.pubkey ];
};
};
nix.trustedUsers = [ config.krebs.build.user.name ];
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
@ -41,8 +42,6 @@ with import <stockholm/lib>;
};
boot.tmpOnTmpfs = true;
systemd.tmpfiles.rules = [
"d /tmp 1777 root root - -"
@ -61,7 +60,7 @@ with import <stockholm/lib>;
environment.shellAliases = {
# TODO: see .aliases
lsl = "ls -lAtr";
dmesg = "journalctl -kb | cat";
dmesg = "dmesg -L --reltime";
psg = "ps -ef | grep";
nmap = "nmap -oN $HOME/loot/scan-`date +\%s`.nmap -oX $HOME/loot/scan-`date +%s`.xml";
grep = "grep --color=auto";

View File

@ -0,0 +1,15 @@
let
fqdn = "board.euer.krebsco.de";
port = 13113;
in {
services.restya-board = {
enable = true;
virtualHost.listenPort = port;
};
services.nginx.virtualHosts."${fqdn}" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://localhost:${toString port}";
};
}

View File

@ -0,0 +1,39 @@
{ lib, ... }:
with lib;
let
port = ident: toString (28000 + ident);
instances = [ 1 2 3 4 5 6 7 8 9 ];
in {
services.nginx.recommendedProxySettings = true;
services.nginx.virtualHosts."warrior.gum.r".locations = let
# TODO location "/" shows all warrior instances
proxy = ident:
{
"/warrior${toString ident}/" = {
proxyPass = "http://localhost:${port ident}/";
# rewrite ^/info /warrior${toString ident}/info;
extraConfig = ''
sub_filter "http://warrior.gum.r/info" "http://warrior.gum.r/warrior${toString ident}/info";
sub_filter_once off;
'';
};
};
in
foldl' mergeAttrs {} (map proxy instances);
docker-containers = let
container = ident:
{ "archiveteam-warrior${toString ident}" = {
image = "archiveteam/warrior-dockerfile";
ports = [ "127.0.0.1:${port ident}:8001" ];
environment = {
DOWNLOADER = "makefu";
SELECTED_PROJECT = "auto";
CONCURRENT_ITEMS = "6";
WARRIOR_ID = toString ident;
};
};
};
in
foldl' mergeAttrs {} (map container instances);
}

View File

@ -0,0 +1,43 @@
{ config, lib, pkgs, ... }:
# more than just nginx config but not enough to become a module
let
wsgi-sock = "${workdir}/uwsgi-gecloudpad.sock";
workdir = config.services.uwsgi.runDir;
gecloudpad = pkgs.python3Packages.callPackage ./gecloudpad.nix {};
in {
services.uwsgi = {
enable = true;
user = "nginx";
# runDir = "/var/lib/photostore";
plugins = [ "python3" ];
instance = {
type = "emperor";
vassals = {
gecloudpad = {
type = "normal";
pythonPackages = self: with self; [ gecloudpad ];
socket = wsgi-sock;
};
};
};
};
services.nginx = {
enable = lib.mkDefault true;
virtualHosts."pad.binaergewitter.de" = {
enableACME = true;
forceSSL = true;
locations = {
"/".extraConfig = ''
expires -1;
uwsgi_pass unix://${wsgi-sock};
uwsgi_param UWSGI_CHDIR ${gecloudpad}/${pkgs.python.sitePackages};
uwsgi_param UWSGI_MODULE gecloudpad.main;
uwsgi_param UWSGI_CALLABLE app;
include ${pkgs.nginx}/conf/uwsgi_params;
'';
};
};
};
}

View File

@ -0,0 +1,24 @@
{ lib, pkgs, fetchFromGitHub, ... }:
with pkgs.python3Packages;buildPythonPackage rec {
name = "gecloudpad-${version}";
version = "0.2.3";
propagatedBuildInputs = [
flask requests
];
src = fetchFromGitHub {
owner = "binaergewitter";
repo = "gecloudpad";
rev = "master";
sha256 = "0p9lcphp3r7hyypxadzw4x9ix6d0anmspxnjnj0v2jjll8gxqlhf";
};
meta = {
homepage = https://github.com/binaergeiwtter/gecloudpad;
description = "server side for gecloudpad";
license = lib.licenses.wtfpl;
};
}

View File

@ -0,0 +1,14 @@
let
fqdn = "rss.euer.krebsco.de";
in {
services.tt-rss = {
enable = true;
virtualHost = fqdn;
selfUrlPath = "https://${fqdn}";
};
services.nginx.virtualHosts."${fqdn}" = {
enableACME = true;
forceSSL = true;
};
}

View File

@ -0,0 +1,38 @@
{ lib
, buildPythonPackage
, fetchPypi
, cryptography
, pyasn1
, rsa
, pycryptodome
}:
buildPythonPackage rec {
pname = "adb_shell";
version = "0.0.8";
src = fetchPypi {
inherit pname version;
sha256 = "01f9jinhfyjldg9793gz2i7gcd9xyx0a62r7a5ijssklcnn2rwnm";
};
propagatedBuildInputs = [
cryptography
pyasn1
rsa
];
# tests are not part of pypi package
doCheck = false;
checkInputs = [
pycryptodome
];
meta = with lib; {
description = "A Python implementation of ADB with shell and FileSync functionality";
homepage = https://github.com/JeffLIrion/adb_shell/;
license = licenses.mit;
# maintainers = [ maintainers. ];
};
}

View File

@ -0,0 +1,30 @@
{ lib
, buildPythonPackage
, callPackage
, fetchPypi
}:
buildPythonPackage rec {
pname = "androidtv";
version = "0.0.34";
src = fetchPypi {
inherit pname version;
sha256 = "13078i2a9hglpv4ldycph5n5485np21vs6z2qn830hybmx8kfxsw";
};
propagatedBuildInputs = [
(callPackage ./adbshell.nix {})
(callPackage ./purepythonadb.nix {})
];
# tests are not packaged in pypi release
doCheck = false;
meta = with lib; {
description = "Communicate with an Android TV or Fire TV device via ADB over a network";
homepage = https://github.com/JeffLIrion/python-androidtv/;
license = licenses.mit;
# maintainers = [ maintainers. ];
};
}

View File

@ -0,0 +1,21 @@
{ lib
, buildPythonPackage
, fetchPypi
}:
buildPythonPackage rec {
pname = "pure-python-adb";
version = "0.2.3.dev0";
src = fetchPypi {
inherit pname version;
sha256 = "88e5a4578435197799aa368fb1a5d87fe43e02a888cb7e85c2ad66173b383c89";
};
meta = with lib; {
description = "Pure python implementation of the adb client";
homepage = https://github.com/Swind/pure-python-adb;
license = licenses.mit;
# maintainers = [ maintainers. ];
};
}

View File

@ -0,0 +1,33 @@
let
cmd = command: {
service = "androidtv.adb_command";
data = {
entity_id = "media_player.firetv_stick";
inherit command;
};
};
sec = seconds: { delay.seconds = seconds; };
in [
{
alias = "Nightly reboot of firetv";
trigger = {
platform = "time";
at = "03:00:00";
};
action = [
(cmd "reboot")
(sec 90) # go to my music because apparently select_source does not seem to always work
(cmd "HOME")
(sec 2)
(cmd "DOWN")
(sec 2)
(cmd "DOWN")
(sec 2)
(cmd "ENTER")
(sec 4)
(cmd "RIGHT")
(sec 2)
(cmd "RIGHT")
];
}
]

View File

@ -0,0 +1,152 @@
{ pkgs, lib, config, ... }:
# Ideas:
## wake-on-lan server
##
let
upkgs = (import <nixpkgs-unstable> {}).pkgs;
hlib = (import ./lib);
prefix = hlib.prefix;
tasmota = hlib.tasmota;
firetv_stick = "192.168.1.24";
hassdir = "/var/lib/hass";
zigbee = import ./multi/zigbee2mqtt.nix;
#flurlicht = import ./multi/flurlicht.nix;
kurzzeitwecker = import ./multi/kurzzeitwecker.nix;
firetv_restart = import ./multi/firetv_restart.nix;
# switch
# automation
# binary_sensor
# sensor
# input_select
# timer
in {
imports = [
./mqtt.nix
];
services.home-assistant = {
package = (upkgs.home-assistant.overrideAttrs (old: {
})).override {
extraPackages = ps: with ps; [
python-forecastio jsonrpc-async jsonrpc-websocket mpd2 pkgs.picotts
(ps.callPackage ./androidtv {})
];
};
config = {
input_select = zigbee.input_select; # dict
timer = zigbee.timer // kurzzeitwecker.timer; # dict
homeassistant = {
name = "Home"; time_zone = "Europe/Berlin";
latitude = "48.7687";
longitude = "9.2478";
elevation = 247;
};
discovery = {};
conversation = {};
history = {};
logbook = {};
logger = {
default = "info";
};
tts = [
{ platform = "google_translate";
language = "de";
time_memory = 57600;
service_name = "google_say";
}
];
telegram_bot = [
# secrets file: {
# "platform": "broadcast",
# "api_key": "", # talk to Botfather /newbot
# "allowed_chat_ids": [ ID ] # curl -X GET # https://api.telegram.org/bot<YOUR_API_TOKEN>/getUpdates
#}
(builtins.fromJSON
(builtins.readFile <secrets/hass/telegram-bot.json>))
];
notify = [
{
platform = "kodi";
name = "wohnzimmer";
host = firetv_stick;
}
{
platform = "telegram";
name = "telegrambot";
chat_id = builtins.elemAt
(builtins.fromJSON (builtins.readFile
<secrets/hass/telegram-bot.json>)).allowed_chat_ids 0;
}
];
sun.elevation = 247;
recorder = {};
media_player = [
{ platform = "FireTV Stick kodi";
host = firetv_stick;
}
{ platform = "androidtv";
name = "FireTV Stick";
device_class = "firetv";
# adb_server_ip = firetv_stick;
host = firetv_stick;
port = 5555;
}
];
mqtt = {
broker = "localhost";
discovery = true; #enable esphome discovery
discovery_prefix = "homeassistant";
port = 1883;
client_id = "home-assistant";
username = "hass";
password = lib.removeSuffix "\n" (builtins.readFile <secrets/mqtt/hass>);
keepalive = 60;
protocol = 3.1;
birth_message = {
topic = "${prefix}/hass/tele/LWT";
payload = "Online";
qos = 1;
retain = true;
};
will_message = {
topic = "${prefix}/hass/tele/LWT";
payload = "Offline";
qos = 1;
retain = true;
};
};
luftdaten = {
show_on_map = true;
sensor_id = 679;
sensors.monitored_conditions = [ "P1" "P2" ];
};
#binary_sensor =
# flurlicht.binary_sensor;
sensor = [
{ platform = "speedtest";
monitored_conditions = [ "ping" "download" "upload" ];
}
# https://www.home-assistant.io/cookbook/automation_for_rainy_days/
]
++ ((import ./sensor/outside.nix) {inherit lib;})
++ zigbee.sensor ;
frontend = { };
# light = flurlicht.light;
http = { };
switch = [];
automation = []
++ (import ./automation/firetv_restart.nix)
++ kurzzeitwecker.automation
#++ flurlicht.automation
++ zigbee.automation;
script =
{ }
// kurzzeitwecker.script; # dict
};
enable = true;
configDir = hassdir;
};
}

View File

@ -0,0 +1,44 @@
let
prefix = "/ham";
in
{
inherit prefix;
say = let
# returns a list of actions to be performed on an mpd to say something
tts = { message, entity }:
[
{
service = "media_player.turn_on";
data.entity_id = entity;
}
{
service = "media_player.play_media";
data = {
entity_id = entity;
media_content_type = "playlist";
media_content_id = "ansage";
};
}
{
service = "media_player.turn_on";
data.entity_id = entity;
}
{ delay.seconds = 8; }
{
service = "tts.say";
entity_id = entity;
data_template = {
inherit message;
language = "de";
};
}
];
in
{
firetv = message: tts {
inherit message;
entity = "firetv";
};
};
zigbee.prefix = "/ham/zigbee";
}

View File

@ -0,0 +1,57 @@
# provides:
# light
# automation
# binary_sensor
let
hlib = (import ../lib);
tasmota = hlib.tasmota;
in
{
binary_sensor = [
(tasmota.motion { name = "Flur Bewegung"; host = "flurlicht";})
];
light = [ (tasmota.rgb { name = "Flurlicht"; host = "flurlicht";} ) ];
automation = [
{ alias = "Dunkel bei Sonnenuntergang";
trigger = {
platform = "sun";
event = "sunset";
# offset: "-00:45:00"
};
action = [
{
service= "light.turn_on";
data = {
entity_id= "light.flurlicht";
# rgb_color = [ 0,0,0 ]; <-- TODO default color
brightness_pct = 15;
};
}
{
service= "light.turn_off";
entity_id= "light.flurlicht";
}
];
}
{ alias = "Hell bei Sonnenaufgang";
trigger = {
platform = "sun";
event = "sunrise";
# offset: "-00:00:00"
};
action = [
{
service= "light.turn_on";
data = {
entity_id= "light.flurlicht";
brightness_pct = 85;
};
}
{
service= "light.turn_off";
entity_id= "light.flurlicht";
}
];
}
];
}

View File

@ -0,0 +1,132 @@
# Provides:
# timer
# automation
# script
# Needs:
# sensor.zigbee_btn1_click
# notify.telegrambot
let
button = "sensor.zigbee_btn2_click";
in {
timer.kurzzeitwecker =
{
name = "Zigbee Kurzzeitwecker";
duration = 300;
};
script.add_5_minutes_to_kurzzeitwecker =
{
alias = "Add 5 minutes to kurzzeitwecker";
sequence = [
{ service = "timer.pause";
entity_id = "timer.kurzzeitwecker";
}
{ service = "timer.start";
data_template = {
entity_id = "timer.kurzzeitwecker";
duration = ''
{% set r = state_attr('timer.kurzzeitwecker', 'remaining') ~ '-0000' %}
{% set t = strptime(r, '%H:%M:%S.%f%z') %}
{{ (as_timestamp(t) + 300) | timestamp_custom('%H:%M:%S', false) }}
'';
};
}
];
};
automation =
[
{
alias = "Start Timer 5min";
trigger = {
platform = "state";
entity_id = button;
to = "single";
};
condition =
{ condition = "state";
entity_id = "timer.kurzzeitwecker";
state = "idle";
};
action = [
{ service = "timer.start";
entity_id = "timer.kurzzeitwecker";
data.duration = "00:05:00";
}
{
service = "notify.telegrambot";
data.message = "Timer gestartet {{state_attr('timer.kurzzeitwecker', 'remaining') }}, verbleibend ";
}
];
}
{
alias = "Add Timer 5min";
trigger = {
platform = "state";
entity_id = button;
to = "single";
};
condition =
{ condition = "state";
entity_id = "timer.kurzzeitwecker";
state = "active";
};
action = [
{ service = "homeassistant.turn_on";
entity_id = "script.add_5_minutes_to_kurzzeitwecker";
}
{
service = "notify.telegrambot";
data.message = ''Timer um 5 minuten verlängert, {{ state_attr('timer.kurzzeitwecker', 'remaining') | truncate(9,True," ") }} verbleibend '';
}
];
}
{
alias = "Stop timer on double click";
trigger = [
{
platform = "state";
entity_id = button;
to = "double";
}
{
platform = "state";
entity_id = button;
to = "triple";
}
];
condition =
{
condition = "state";
entity_id = "timer.kurzzeitwecker";
state = "active";
};
action = [
{
service = "timer.cancel";
entity_id = "timer.kurzzeitwecker";
}
{
service = "notify.telegrambot";
data.message = "Timer gestoppt, abgebrochen";
}
];
}
{
alias = "Timer Finished";
trigger = {
platform = "event";
event_type = "timer.finished";
event_data.entity_id = "timer.kurzzeitwecker";
};
action = [
{
service = "notify.telegrambot";
data.message = "Timer beendet";
}
];
}
];
}

View File

@ -0,0 +1,129 @@
# provides:
# switch
# automation
# binary_sensor
# sensor
# input_select
# timer
let
inherit (import ../lib) zigbee;
prefix = zigbee.prefix;
in {
sensor =
[
# Sensor for monitoring the bridge state
{
platform = "mqtt";
name = "Zigbee2mqtt Bridge state";
state_topic = "${prefix}/bridge/state";
icon = "mdi:router-wireless";
}
# Sensor for Showing the Zigbee2mqtt Version
{
platform = "mqtt";
name = "Zigbee2mqtt Version";
state_topic = "${prefix}/bridge/config";
value_template = "{{ value_json.version }}";
icon = "mdi:zigbee";
}
# Sensor for Showing the Coordinator Version
{
platform = "mqtt";
name = "Coordinator Version";
state_topic = "${prefix}/bridge/config";
value_template = "{{ value_json.coordinator }}";
icon = "mdi:chip";
}
];
switch = [
{
platform = "mqtt";
name = "Zigbee2mqtt Main join";
state_topic = "${prefix}/bridge/config/permit_join";
command_topic = "${prefix}/bridge/config/permit_join";
payload_on = "true";
payload_off = "false";
}
];
automation = [
{
alias = "Zigbee2mqtt Log Level";
initial_state = "on";
trigger = {
platform = "state";
entity_id = "input_select.zigbee2mqtt_log_level";
};
action = [
{
service = "mqtt.publish";
data = {
payload_template = "{{ states('input_select.zigbee2mqtt_log_level') }}";
topic = "${prefix}/bridge/config/log_level";
};
}
];
}
# Automation to start timer when enable join is turned on
{
id = "zigbee_join_enabled";
alias = "Zigbee Join Enabled";
hide_entity = "true";
trigger =
{
platform = "state";
entity_id = "switch.zigbee2mqtt_main_join";
to = "on";
};
action =
{
service = "timer.start";
entity_id = "timer.zigbee_permit_join";
};
}
# # Automation to stop timer when switch turned off and turn off switch when timer finished
{
id = "zigbee_join_disabled";
alias = "Zigbee Join Disabled";
hide_entity = "true";
trigger = [
{
platform = "event";
event_type = "timer.finished";
event_data.entity_id = "timer.zigbee_permit_join";
}
{
platform = "state";
entity_id = "switch.zigbee2mqtt_main_join";
to = "off";
}
];
action = [
{ service = "timer.cancel";
data.entity_id = "timer.zigbee_permit_join";
}
{ service = "switch.turn_off";
entity_id = "switch.zigbee2mqtt_main_join";
}
];
}
];
input_select.zigbee2mqtt_log_level =
{
name = "Zigbee2mqtt Log Level";
options = [
"debug"
"info"
"warn"
"error"
];
initial = "info";
icon = "mdi:format-list-bulleted";
};
timer.zigbee_permit_join =
{
name = "Zigbee Time remaining";
duration = 120;
};
}

View File

@ -0,0 +1,20 @@
{lib,...}: [
{ platform = "darksky";
api_key = lib.removeSuffix "\n"
(builtins.readFile <secrets/hass/darksky.apikey>);
language = "de";
monitored_conditions = [
"summary" "icon"
"nearest_storm_distance" "precip_probability"
"precip_intensity"
"temperature" # "temperature_high" "temperature_low"
"apparent_temperature"
"hourly_summary" # next 24 hours text
"humidity"
"pressure"
"uv_index"
];
units = "si" ;
scan_interval = "00:30:00";
}
]

View File

@ -0,0 +1,20 @@
{config, pkgs, lib, ...}:
{
# symlink the zigbee controller
services.udev.extraRules = ''
SUBSYSTEM=="tty", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="16a8", SYMLINK+="cc2531", MODE="0660", GROUP="dailout"
'';
system.activationScripts.installZigbee = ''
install -d /var/lib/zigbee2mqtt
'';
docker-containers.zigbee2mqtt = {
image = "koenkk/zigbee2mqtt";
extraDockerOptions = [ "--device=/dev/cc2531:/dev/cc2531" ];
volumes = ["/var/lib/zigbee2mqtt:/app/data"];
};
state = [ "/var/lib/zigbee2mqtt/configuration.yaml" "/var/lib/zigbee2mqtt/state.json" ];
}

View File

@ -1,6 +1,8 @@
{
home-manager.users.makefu = {
programs.mbsync.enable = true;
accounts.email.maildirBasePath = "/home/makefu/Mail";
accounts.email.certificatesFile = "/etc/ssl/certs/ca-certificates.crt";
accounts.email.accounts.syntaxfehler = {
address = "felix.richter@syntax-fehler.de";
userName = "Felix.Richter@syntax-fehler.de";
@ -10,18 +12,34 @@
enable = true;
};
};
mbsync = {
enable = true;
create = "both";
remove = "both";
expunge = "both";
patterns = [ "*" "!INBOX.Sent*"];
};
smtp = {
host = "syntax-fehler.de";
tls = {
enable = true;
};
};
folders = {
sent = "Sent";
trash = "Trash";
inbox = "INBOX";
drafts = "Drafts";
};
msmtp.enable = true;
notmuch.enable = true;
offlineimap = {
enable = true;
postSyncHookCommand = "notmuch new";
extraConfig.remote = {
auth_mechanisms = "LOGIN";
tls_level = "tls_secure";
ssl_version = "tls1_2";
holdconnectionopen = true;
idlefolders = "['INBOX']";
};

View File

@ -2,65 +2,8 @@
{
imports = [
{ #direnv
home-manager.users.makefu.home.packages = [ pkgs.direnv ];
home-manager.users.makefu.home.file.".direnvrc".text = ''
use_nix() {
local path="$(nix-instantiate --find-file nixpkgs)"
if [ -f "$${path}/.version-suffix" ]; then
local version="$(< $path/.version-suffix)"
elif [ -f "$path/.version" ]; then
local version="$(< $path/.version)"
else
local version="$(< $(< $path/.git/HEAD))"
fi
local cache=".direnv/cache-''${version:-unknown}"
if [[ ! -e "$cache" ]] || \
[[ "$HOME/.direnvrc" -nt "$cache" ]] || \
[[ .envrc -nt "$cache" ]] || \
[[ default.nix -nt "$cache" ]] || \
[[ shell.nix -nt "$cache" ]];
then
[ -d .direnv ] || mkdir .direnv
local tmp=$(nix-shell --show-trace "$@" \
--run "\"$direnv\" dump zsh")
echo "$tmp" > "$cache"
fi
local path_backup=$PATH term_backup=$TERM
. "$cache"
export PATH=$PATH:$path_backup TERM=$term_backup
if [[ $# = 0 ]]; then
watch_file default.nix
watch_file shell.nix
fi
}
'';
home-manager.users.makefu.programs.zsh.initExtra = ''
nixify() {
if [ ! -e ./.envrc ]; then
echo "use nix" > .envrc
direnv allow
fi
if [ ! -e default.nix ]; then
cat > default.nix <<'EOF'
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "env";
buildInputs = [
bashInteractive
];
}
EOF
''${EDITOR:-vim} default.nix
fi
}
eval "$(direnv hook zsh)"
'';
home-manager.users.makefu.home.packages = [ pkgs.direnv pkgs.nur.repos.kalbasit.nixify ];
# home-manager.users.makefu.home.file.".direnvrc".text = '''';
}
{ # bat
home-manager.users.makefu.home.packages = [ pkgs.bat ];

View File

@ -1,305 +0,0 @@
{ pkgs, lib, config, ... }:
# Ideas:
## wake-on-lan server
##
let
tasmota_rgb = name: topic:
# LED WS2812b
# effect_state_topic: "stat/led/Scheme"
# effect_command_topic: "cmnd/led/Scheme"
# effect_value_template: "{{ value_json.Scheme }}"
{ platform = "mqtt";
inherit name;
retain = false;
qos = 1;
optimistic = false;
# state
# TODO: currently broken, will not use the custom state topic
#state_topic = "/ham/${topic}/stat/POWER";
state_topic = "/ham/${topic}/stat/POWER";
command_topic = "/ham/${topic}/cmnd/POWER";
availability_topic = "/ham/${topic}/tele/LWT";
payload_on= "ON";
payload_off= "OFF";
payload_available= "Online";
payload_not_available= "Offline";
# brightness
brightness_state_topic = "/ham/${topic}/stat/Dimmer";
brightness_command_topic = "/ham/${topic}/cmnd/Dimmer";
brightness_value_template = "{{ value_json.Dimmer }}";
brightness_scale = 100;
# color
rgb_state_topic = "/ham/${topic}/stat/Color";
rgb_command_topic = "/ham/${topic}/cmnd/MEM1"; # use enabled tasmota rule
rgb_command_mode = "hex";
rgb_command_template = "{{ '%02x%02x%02x' | format(red, green, blue)}}";
# effects
effect_state_topic = "/ham/${topic}/stat/Scheme";
effect_command_topic = "/ham/${topic}/cmnd/Scheme";
effect_value_template = "{{ value_json.Scheme }}";
effect_list = [ 0 1 2 3 4 5 6 7 8 9 10 11 12 ];
};
# switchmode 1 - also toggle power
# switchtopic flurlicht
tasmota_motion = name: topic:
{ platform = "mqtt";
device_class = "motion";
inherit name;
# TODO: currently broken, will not use the custom state topic
state_topic = "/ham/${topic}/stat/POWER";
payload_on = "ON";
payload_off = "OFF";
availability_topic = "/ham/${topic}/tele/LWT";
payload_available = "Online";
payload_not_available = "Offline";
};
firetv = "192.168.1.183";
hassdir = "/var/lib/hass";
tasmota_plug = name: topic:
{ platform = "mqtt";
inherit name;
state_topic = "/ham/${topic}/stat/POWER1";
command_topic = "/ham/${topic}/cmnd/POWER1";
availability_topic = "/ham/${topic}/tele/LWT";
payload_on= "ON";
payload_off= "OFF";
payload_available= "Online";
payload_not_available= "Offline";
};
tasmota_bme = name: topic:
[ { platform = "mqtt";
name = "${name} Temperatur";
state_topic = "/ham/${topic}/tele/SENSOR";
value_template = "{{ value_json.BME280.Temperature }}";
unit_of_measurement = "°C";
}
{ platform = "mqtt";
name = "${name} Luftfeuchtigkeit";
state_topic = "/ham/${topic}/tele/SENSOR";
value_template = "{{ value_json.BME280.Humidity }}";
unit_of_measurement = "%";
}
{ platform = "mqtt";
name = "${name} Luftdruck";
state_topic = "/ham/${topic}/tele/SENSOR";
value_template = "{{ value_json.BME280.Pressure }}";
unit_of_measurement = "hPa";
}
];
tasmota_am2301 = name: topic:
[ { platform = "mqtt";
name = "${name} Temperatur";
state_topic = "/ham/${topic}/tele/SENSOR";
value_template = "{{ value_json.AM2301.Temperature }}";
unit_of_measurement = "°C";
}
{ platform = "mqtt";
name = "${name} Luftfeuchtigkeit";
state_topic = "/ham/${topic}/tele/SENSOR";
value_template = "{{ value_json.AM2301.Humidity }}";
unit_of_measurement = "%";
}
];
in {
imports = [
./mqtt.nix
];
services.home-assistant = {
config = {
homeassistant = {
name = "Home"; time_zone = "Europe/Berlin";
latitude = "48.7687";
longitude = "9.2478";
elevation = 247;
};
#discovery = {};
conversation = {};
history = {};
logbook = {};
tts = [
{ platform = "google";}
];
sun.elevation = 247;
recorder = {};
media_player = [
{ platform = "kodi";
host = firetv;
}
{ platform = "firetv";
name = "FireTV Stick";
host = firetv;
adbkey = <secrets/hass/adbkey>;
}
];
mqtt = {
broker = "localhost";
port = 1883;
client_id = "home-assistant";
username = "hass";
password = lib.removeSuffix "\n" (builtins.readFile <secrets/mqtt/hass>);
keepalive = 60;
protocol = 3.1;
birth_message = {
topic = "/ham/hass/tele/LWT";
payload = "Online";
qos = 1;
retain = true;
};
will_message = {
topic = "/ham/hass/tele/LWT";
payload = "Offline";
qos = 1;
retain = true;
};
};
binary_sensor = [
(tasmota_motion "Flur Bewegung" "flurlicht")
];
sensor = [
# broken
#{ platform = "speedtest";
# monitored_conditions = [ "ping" "download" "upload" ];
#}
{ platform = "luftdaten";
name = "Wangen";
sensorid = "663";
monitored_conditions = [ "P1" "P2" ];
}
# https://www.home-assistant.io/cookbook/automation_for_rainy_days/
{ platform = "darksky";
api_key = lib.removeSuffix "\n"
(builtins.readFile <secrets/hass/darksky.apikey>);
language = "de";
monitored_conditions = [ "summary" "icon"
"nearest_storm_distance" "precip_probability"
"precip_intensity"
"temperature"
"apparent_temperature"
"hourly_summary"
"humidity"
"pressure"
"uv_index" ];
units = "si" ;
update_interval = {
days = 0;
hours = 0;
minutes = 30;
seconds = 0;
};
}
]
++ (tasmota_bme "Schlafzimmer" "schlafzimmer")
++ (tasmota_am2301 "Arbeitszimmer" "arbeitszimmer");
frontend = { };
group =
{ default_view =
{ view = "yes";
entities = [
"group.flur"
"group.schlafzimmer"
"group.draussen"
"group.wohnzimmer"
"group.arbeitszimmer"
];
};
flur = [
"light.flurlicht"
"binary_sensor.flur_bewegung"
"automation.dunkel_bei_sonnenuntergang"
"automation.hell_bei_sonnenaufgang"
];
wohnzimmer = [
"media_player.kodi"
"media_player.firetv_stick"
];
draussen = [
"sensor.dark_sky_temperature"
"sensor.dark_sky_hourly_summary"
"sensor.wangen_pm10"
"sensor.wangen_pm25"
];
schlafzimmer = [
"sensor.schlafzimmer_temperatur"
"sensor.schlafzimmer_luftdruck"
"sensor.schlafzimmer_luftfeuchtigkeit"
"switch.lichterkette_schlafzimmer"
];
arbeitszimmer = [
"switch.strom_staubsauger"
"sensor.arbeitszimmer_temperatur"
"sensor.arbeitszimmer_luftfeuchtigkeit"
];
};
http = { };
switch = [
(tasmota_plug "Lichterkette Schlafzimmer" "schlafzimmer")
(tasmota_plug "Strom Staubsauger" "arbeitszimmer")
];
light = [ (tasmota_rgb "Flurlicht" "flurlicht" ) ];
automation = [
{ alias = "Dunkel bei Sonnenuntergang";
trigger = {
platform = "sun";
event = "sunset";
# offset: "-00:45:00"
};
action = [
{
service= "light.turn_on";
data = {
entity_id= "light.flurlicht";
# rgb_color = [ 0,0,0 ]; <-- TODO default color
brightness_pct = 15;
};
}
{
service= "light.turn_off";
entity_id= "light.flurlicht";
}
];
}
{ alias = "Hell bei Sonnenaufgang";
trigger = {
platform = "sun";
event = "sunrise";
# offset: "-00:00:00"
};
action = [
{
service= "light.turn_on";
data = {
entity_id= "light.flurlicht";
brightness_pct = 85;
};
}
{
service= "light.turn_off";
entity_id= "light.flurlicht";
}
];
}
{ alias = "Staubsauger Strom aus nach 6h";
trigger = {
platform = "state";
entity_id = "switch.strom_staubsauger";
to = "on";
for.hours = 6;
};
action = {
service= "homeassistant.turn_off";
entity_id= "switch.strom_staubsauger";
};
}
];
};
enable = true;
configDir = hassdir;
};
nixpkgs.config.permittedInsecurePackages = [
"homeassistant-0.77.2"
];
}

View File

@ -40,10 +40,4 @@
'';
};
services.dbus.packages = [ pkgs.blueman ];
nixpkgs.overlays = [
(self: super: {
blueman = super.blueman.overrideAttrs (oldAttrs: {
buildInputs = oldAttrs.buildInputs ++ [ self.gnome3.adwaita-icon-theme ];
});
})];
}

View File

@ -0,0 +1,10 @@
{ config, lib, pkgs, ... }:
{
users.users.${config.krebs.build.user.name}.extraGroups = [ "dialout" ];
services.udev.extraRules = ''
SUBSYSTEM=="tty", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="16a8", SYMLINK+="cc2531", MODE="0660", GROUP="dailout"
'';
}

View File

@ -68,11 +68,10 @@ in {
};
security.sudo.extraConfig = "${config.krebs.power-action.user} ALL= (root) NOPASSWD: ${pkgs.systemd}/bin/systemctl suspend";
services.redshift = {
enable = true;
latitude = "48.7";
longitude = "9.1";
};
services.redshift.enable = true;
location.latitude = 48.7;
location.longitude = 9.1;
systemd.services.look-up = {
startAt = "*:30";
serviceConfig = {

View File

@ -74,11 +74,7 @@
};
# suppress chrome autit event messages
security.audit = {
rules = [
"-a task,never"
];
};
security.audit.rules = [ "-a task,never" ];
# Enable IPv6 Privacy Extensions
boot.kernel.sysctl = {

View File

@ -6,7 +6,7 @@
users = {};
# TODO: secure that shit
aclExtraConf = ''
pattern readwrite /#
pattern readwrite #
'';
allowAnonymous = true;
};

View File

@ -15,7 +15,6 @@ let
in {
services.phpfpm = {
# phpfpm does not have an enable option
poolConfigs = {
mpd = ''
user = ${user}

View File

@ -1,6 +1,10 @@
{ pkgs, ... }:{
nixpkgs.config.packageOverrides = pkgs: {
nur = import (builtins.fetchTarball "https://github.com/nix-community/NUR/archive/master.tar.gz") {
nur = import (builtins.fetchTarball {
url = "https://github.com/nix-community/NUR/archive/7bfd0117b359d0f72d086ff7e1f0ba3aeaf8d91e.tar.gz";
sha256 = "0gb2np1r2m9kkz1s374gxdqrwhkzx48iircy00y6mjr7h14rhyxk";
}
){
inherit pkgs;
};
};

Some files were not shown because too many files have changed in this diff Show More