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