2020-04-17 20:59:12 +02:00
|
|
|
{ lib, config, pkgs, ... }:
|
|
|
|
let
|
|
|
|
|
|
|
|
folderPath = config.services.home-assistant.configDir;
|
|
|
|
|
|
|
|
# find symbols with
|
|
|
|
# https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords=<keywords>&apikey=<api_key>
|
|
|
|
# as described here : https://www.alphavantage.co/documentation/#symbolsearch
|
|
|
|
#
|
|
|
|
# example:
|
|
|
|
# --------
|
|
|
|
# stocks = [
|
|
|
|
# {
|
|
|
|
# symbol = "GOOGL";
|
|
|
|
# name = "google";
|
|
|
|
# friendly_name = "Google";
|
|
|
|
# currency = "$";
|
|
|
|
# # I own 50 and bought at a price of 1000
|
|
|
|
# own = {
|
|
|
|
# pieces = 50;
|
|
|
|
# price = 1000;
|
|
|
|
# };
|
|
|
|
# }
|
|
|
|
# ];
|
|
|
|
stocks = import <secrets/home-assistant/stocks>;
|
|
|
|
filePath = name: "${folderPath}/stock_${name}.json";
|
|
|
|
|
|
|
|
cleanup_list = list: lib.filter (entry: entry != { }) (lib.flatten list);
|
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
in
|
|
|
|
{
|
2020-04-17 20:59:12 +02:00
|
|
|
services.homeAssistantConfig = {
|
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
sensor = cleanup_list (map
|
|
|
|
({ name, currency, own ? { }, ... }: [
|
|
|
|
{
|
|
|
|
platform = "file";
|
|
|
|
name = "stock_${name}";
|
|
|
|
file_path = filePath name;
|
|
|
|
value_template = "{{ value_json.price}} ${currency}";
|
2020-04-17 20:59:12 +02:00
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
}
|
|
|
|
{
|
|
|
|
platform = "file";
|
|
|
|
name = "stock_${name}_change";
|
|
|
|
file_path = filePath name;
|
|
|
|
value_template = "{{ value_json.change}} ${currency}";
|
2020-04-17 20:59:12 +02:00
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
}
|
|
|
|
{
|
|
|
|
platform = "file";
|
|
|
|
name = "stock_${name}_change_percent";
|
|
|
|
file_path = filePath name;
|
|
|
|
value_template = "{{ value_json.change_percent}} %";
|
|
|
|
}
|
|
|
|
(lib.optionalAttrs (own != { }) {
|
|
|
|
platform = "file";
|
|
|
|
name = "stock_${name}_profit";
|
|
|
|
file_path = filePath name;
|
|
|
|
value_template = ''
|
|
|
|
{{ "{:,.2f}".format( value_json.price * ${toString own.pieces} - ${
|
|
|
|
toString (own.pieces * own.price)
|
|
|
|
} ) }} ${currency}'';
|
|
|
|
})
|
|
|
|
])
|
|
|
|
stocks);
|
2020-04-17 20:59:12 +02:00
|
|
|
|
|
|
|
homeassistant = {
|
|
|
|
whitelist_external_dirs = [ folderPath ];
|
|
|
|
customize = builtins.listToAttrs (cleanup_list (map
|
|
|
|
({ name, own ? { }, ... }: [
|
|
|
|
{
|
|
|
|
name = "sensor.stock_${name}";
|
|
|
|
value = {
|
|
|
|
icon = "mdi:cash-usd-outline";
|
|
|
|
friendly_name = "Price";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name = "sensor.stock_${name}_change";
|
|
|
|
value = {
|
|
|
|
icon = "mdi:radar";
|
|
|
|
friendly_name = "Difference";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name = "sensor.stock_${name}_change_percent";
|
|
|
|
value = {
|
|
|
|
icon = "mdi:radar";
|
|
|
|
friendly_name = "Percent";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
(lib.optionalAttrs (own != { }) {
|
|
|
|
name = "sensor.stock_${name}_profit";
|
|
|
|
value = {
|
|
|
|
icon = "mdi:radar";
|
|
|
|
friendly_name = "Profit";
|
|
|
|
};
|
|
|
|
})
|
2021-11-01 09:20:42 +01:00
|
|
|
])
|
|
|
|
stocks));
|
2020-04-17 20:59:12 +02:00
|
|
|
};
|
|
|
|
|
2020-06-01 23:20:15 +02:00
|
|
|
group = (builtins.listToAttrs (map
|
|
|
|
({ name, friendly_name, own ? { }, ... }: {
|
|
|
|
name = "stock_${name}";
|
|
|
|
value = {
|
|
|
|
name = "${friendly_name} Aktie";
|
|
|
|
entities = [
|
|
|
|
"sensor.stock_${name}"
|
|
|
|
"sensor.stock_${name}_change"
|
|
|
|
"sensor.stock_${name}_change_percent"
|
|
|
|
] ++ (lib.optional (own != { }) "sensor.stock_${name}_profit");
|
|
|
|
};
|
2021-11-01 09:20:42 +01:00
|
|
|
})
|
|
|
|
stocks));
|
2020-04-17 20:59:12 +02:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
systemd.services =
|
|
|
|
let
|
|
|
|
pullService = { name, symbol, currency, ... }: {
|
|
|
|
name = "pull_stock_${name}";
|
|
|
|
value = {
|
|
|
|
enable = true;
|
|
|
|
before = [ "home-assistant.service" ];
|
|
|
|
wantedBy = [ "home-assistant.service" ];
|
|
|
|
serviceConfig = {
|
|
|
|
User = "hass";
|
|
|
|
Type = "oneshot";
|
|
|
|
};
|
|
|
|
description = "pull stock_${name} for homeassistant";
|
|
|
|
script = ''
|
|
|
|
SYMBOL="${symbol}"
|
|
|
|
CURRENCY="${currency}"
|
|
|
|
APIKEY=${
|
|
|
|
lib.fileContents <secrets/home-assistant/alphavantage/apikey>
|
|
|
|
}
|
2020-04-17 20:59:12 +02:00
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
${pkgs.curl}/bin/curl --location --silent \
|
|
|
|
"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=$SYMBOL&apikey=$APIKEY" \
|
|
|
|
| ${pkgs.jq}/bin/jq --compact-output \
|
|
|
|
'.["Global Quote"] |
|
|
|
|
{
|
|
|
|
price: .["05. price"] | tonumber,
|
|
|
|
currency: "'$CURRENCY'",
|
|
|
|
change_percent: .["10. change percent"] | .[0:-1] | tonumber,
|
|
|
|
change: .["09. change"] | tonumber,
|
|
|
|
last_date: .["07. latest trading day"],
|
|
|
|
}' \
|
|
|
|
>> ${filePath name}
|
2020-04-17 20:59:12 +02:00
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
# old and stupid
|
|
|
|
#${pkgs.curl}/bin/curl --location --silent \
|
|
|
|
#"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=$SYMBOL&interval=5min&apikey=$APIKEY" \
|
|
|
|
#| ${pkgs.jq}/bin/jq --compact-output \
|
|
|
|
# '.["Time Series (5min)"] | to_entries | [ .[]
|
|
|
|
# | { date : .key , value : .value["4. close"], currency: "'$CURRENCY'" } ]
|
|
|
|
# | sort_by(.date) | reverse | .[0]' \
|
|
|
|
'';
|
|
|
|
};
|
2020-04-17 20:59:12 +02:00
|
|
|
};
|
2021-11-01 09:20:42 +01:00
|
|
|
in
|
|
|
|
builtins.listToAttrs (map pullService stocks);
|
2020-04-17 20:59:12 +02:00
|
|
|
|
2021-11-01 09:20:42 +01:00
|
|
|
systemd.timers =
|
|
|
|
let
|
|
|
|
pullTimer = { name, ... }: {
|
|
|
|
name = "pull_stock_${name}";
|
|
|
|
value = {
|
|
|
|
enable = true;
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = "hourly";
|
|
|
|
Persistent = "true";
|
|
|
|
};
|
2020-04-17 20:59:12 +02:00
|
|
|
};
|
|
|
|
};
|
2021-11-01 09:20:42 +01:00
|
|
|
in
|
|
|
|
builtins.listToAttrs (map pullTimer stocks);
|
2020-04-17 20:59:12 +02:00
|
|
|
|
|
|
|
}
|