diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 767e42c..e174da5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -61,11 +61,9 @@ jobs: fi execute: runs-on: ${{ matrix.os }} - strategy: matrix: os: [ubuntu-latest, macos-latest] - steps: - name: Checkout code uses: actions/checkout@v3 @@ -76,18 +74,21 @@ jobs: else echo "I: Nothing to install for ${{ matrix.os }}" fi + - name: Set script permissions + run: chmod +x ./victron-venus-os-install.sh - name: Install run: ./victron-venus-os-install.sh env: DEBUG: 1 DESTDIR: /tmp/testing - - name: Control - run: scripts/controller.sh + BRANCH: ${{ steps.set-branch-name.outputs.branch_name }} + - name: Execute Run-Script + run: /tmp/testing//data/etc/Spotmarket-Switcher/service/run env: DEBUG: 1 - LOG_FILE: /tmp/testing_controller.log - - name: Run - run: scripts/run + rc_local_file: /tmp/testing_rc.local + - name: Execute Control-Script + run: /tmp/testing//data/etc/Spotmarket-Switcher/controller.sh env: DEBUG: 1 - rc_local_file: /tmp/testing_rc.local + LOG_FILE: /tmp/testing_controller.log diff --git a/.github/workflows/main_versioning.yml b/.github/workflows/main_versioning.yml new file mode 100644 index 0000000..b380174 --- /dev/null +++ b/.github/workflows/main_versioning.yml @@ -0,0 +1,36 @@ +name: Main Versioning + +# This workflow triggers when a pull request to the 'main' branch is closed +on: + pull_request: + types: [closed] + branches: + - main + +jobs: + update_version: + # Ensure this job only runs if the PR was merged, not just closed without merging + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Update VERSION in main + run: | + # Attempt to remove the -DEV suffix from the version number + NEW_VERSION=$(sed -n 's/^VERSION=\"\(.*\)-DEV\"$/\1/p' scripts/controller.sh) + + # If NEW_VERSION is empty (meaning there was no -DEV), take the current value of VERSION + if [[ -z $NEW_VERSION ]]; then + NEW_VERSION=$(sed -n 's/^VERSION=\"\(.*\)\"$/\1/p' scripts/controller.sh) + fi + + # Replace VERSION in the file with the NEW_VERSION value + sed -i "s/^VERSION=\".*\"$/VERSION=\"${NEW_VERSION}\"/" scripts/controller.sh + + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git commit -am "Update version to ${NEW_VERSION}" + git push origin main diff --git a/.github/workflows/venus.yml b/.github/workflows/venus.yml index 6f63c93..4b8aee5 100644 --- a/.github/workflows/venus.yml +++ b/.github/workflows/venus.yml @@ -19,7 +19,7 @@ jobs: if which apt > /dev/null then apt update - apt -y install wget curl + apt -y install wget curl cron elif which opkg > /dev/null then opkg install wget @@ -27,19 +27,24 @@ jobs: else echo "W: Tests limited because of non-avail of wget and curl" fi + - name: Set script permissions + run: chmod +x ./victron-venus-os-install.sh + env: + DEBUG: 1 - name: Execute Installation under Venus OS run: | echo pwd pwd echo ls ls - echo victron-venus-install.sh + echo victron-venus-os-install.sh if ./victron-venus-os-install.sh ; then echo "[OK]" else echo "[FAIL]" pwd - find . | head -n 30 + HEAD_PATH=$(which head) + find . | $HEAD_PATH -n 30 exit 1 fi env: diff --git a/scripts/controller.sh b/scripts/controller.sh old mode 100755 new mode 100644 index dea098d..3adbf79 --- a/scripts/controller.sh +++ b/scripts/controller.sh @@ -28,6 +28,8 @@ License=$( EOLICENSE ) +VERSION="2.3.7" + set -e if [ -z "$LANG" ]; then @@ -125,119 +127,6 @@ fi # Note: This script is only for hourly-based tariff data, please create your own fork for higher resolutions like 15 minute intervals. # After an API reconfiguration please delete the old API-Downloadfiles with rm /tmp/awattar*.* /tmp/entsoe*.* -# Path to the current script directory -DIR="$(dirname "$0")" - -if [ -f "$DIR/config.txt" ]; then - # Include the configuration file - source "$DIR/config.txt" -else - log_info "E: The file $DIR/config.txt was not found! Configure the existing sample.config.txt file and then save it as config.txt in the same directory." false - exit 127 -fi - -if [ -z "$UNAME" ]; then - UNAME=$(uname) -fi -if [ "Darwin" = "$UNAME" ]; then - log_info "W: MacOS has a different implementation of 'date' - use conda if hunting a bug on a mac". -fi - -# further API parameters (no need to edit) -dateInSeconds=$(LC_ALL=C TZ=$TZ date +"%s") -if [ "Darwin" = "$UNAME" ]; then - yesterday=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds - 86400)) +%d)2300 - yestermonth=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds - 86400)) +%m) - yesteryear=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds - 86400)) +%Y) - today=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%d)2300 - today2=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%d) - todaymonth=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%m) - todayyear=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%Y) - tomorrow=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%d)2300 - tomorrow2=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%d) - tomorrowmonth=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%m) - tomorrowyear=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%Y) - getnow=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%k) -else - yesterday=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds - 86400)) +%d)2300 - yestermonth=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds - 86400)) +%m) - yesteryear=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds - 86400)) +%Y) - today=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%d)2300 - today2=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%d) - todaymonth=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%m) - todayyear=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%Y) - tomorrow=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%d)2300 - tomorrow2=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%d) - tomorrowmonth=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%m) - tomorrowyear=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%Y) - getnow=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%k) -fi - -now_linenumber=$((getnow + 1)) -link1="https://api.awattar.$awattar/v1/marketdata/current.yaml" -link2="http://api.awattar.$awattar/v1/marketdata/current.yaml?tomorrow=include" -link3="https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/$latitude%2C%20$longitude/$todayyear-$todaymonth-$today2/$tomorrowyear-$tomorrowmonth-$tomorrow2?unitGroup=metric&elements=solarenergy%2Ccloudcover%2Csunrise%2Csunset&include=days&key=$visualcrossing_api_key&contentType=csv" -link4="https://web-api.tp.entsoe.eu/api?securityToken=$entsoe_eu_api_security_token&documentType=A44&in_Domain=$in_Domain&out_Domain=$out_Domain&periodStart=$yesteryear$yestermonth$yesterday&periodEnd=$todayyear$todaymonth$today" -link5="https://web-api.tp.entsoe.eu/api?securityToken=$entsoe_eu_api_security_token&documentType=A44&in_Domain=$in_Domain&out_Domain=$out_Domain&periodStart=$todayyear$todaymonth$today&periodEnd=$tomorrowyear$tomorrowmonth$tomorrow" -link6="https://api.tibber.com/v1-beta/gql" -file1=/tmp/awattar_today_prices.yaml -file2=/tmp/awattar_tomorrow_prices.yaml -file3=/tmp/expected_solarenergy.csv -file4=/tmp/entsoe_today_prices.xml -file5=/tmp/entsoe_tomorrow_prices.xml -file6=/tmp/awattar_prices.txt -file7=/tmp/awattar_prices_sorted.txt -file8=/tmp/entsoe_prices.txt -file9=/tmp/entsoe_tomorrow_prices_sorted.txt -file10=/tmp/entsoe_today_prices.txt -file11=/tmp/entsoe_today_prices_sorted.txt -file12=/tmp/tibber_prices_sorted.txt -file13=/tmp/entsoe_tomorrow_prices.txt -file14=/tmp/tibber_prices.txt -file15=/tmp/tibber_today_prices.txt -file16=/tmp/tibber_today_prices_sorted.txt -file17=/tmp/tibber_tomorrow_prices.txt -file18=/tmp/tibber_tomorrow_prices_sorted.txt -file19=/tmp/entsoe_prices_sorted.txt - -########## Optional environmental variables - -if [ -z "$LOG_FILE" ]; then - LOG_FILE="/tmp/spotmarket-switcher.log" -fi -if [ -z "$LOG_MAX_SIZE" ]; then - LOG_MAX_SIZE=1024 # 1 MB -fi -if [ -z "$LOG_FILES_TO_KEEP" ]; then - LOG_FILES_TO_KEEP=2 -fi - -########## Testing series of preconditions prior to execution of script - -num_tools_missing=0 -tools="awk curl cat sed sort head tail" -if [ 0 -lt $use_victron_charger ]; then - tools="$tools dbus" - charger_command_turnon="dbus -y com.victronenergy.settings /Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day SetValue -- 7" - charger_command_turnoff="dbus -y com.victronenergy.settings /Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day SetValue -- -7" - SOC_percent=$(dbus-send --system --print-reply --dest=com.victronenergy.system /Dc/Battery/Soc com.victronenergy.BusItem.GetValue | grep variant | awk '{print $3}') # This will get the battery state of charge (SOC) from a Victron Energy system -fi - -for tool in $tools; do - if ! which "$tool" >/dev/null; then - log_info "E: Please ensure the tool '$tool' is found." - num_tools_missing=$((num_tools_missing + 1)) - fi -done - -if [ $num_tools_missing -gt 0 ]; then - log_info "E: $num_tools_missing tools are missing." - exit 127 -fi - -unset num_tools_missing - - ####################################### ### Begin of the functions... ### ####################################### @@ -295,13 +184,24 @@ declare -A valid_vars=( ["tibber_api_key"]="string" ) +# Define a logging function and try out different methods. Maybe log_message is not available at MacOS. +log_message() { + message="$1" + if [ -z "$(command -v log_info)" ]; then + logger -p user.info -t "Spotmarket-Switcher" "$message" + else + log_info "$message" + fi +} + + declare -A config_values parse_and_validate_config() { local file="$1" local errors="" - rotating_spinner & # Start the spinner in the background + rotating_spinner & # Start the spinner in the background local spinner_pid=$! # Get the PID of the spinner # Step 1: Parse @@ -315,7 +215,7 @@ parse_and_validate_config() { # Set the value in the associative array config_values["$key"]="$value" - done < "$file" + done <"$file" # Step 2: Validation for var_name in "${!valid_vars[@]}"; do @@ -376,21 +276,21 @@ download_awattar_prices() { local sleep_time="$4" if [ -z "$DEBUG" ]; then - log_info "I: Please be patient. First we wait $sleep_time seconds in case the system clock is not syncronized and not to overload the API." false + log_message "I: Please be patient. First we wait $sleep_time seconds in case the system clock is not syncronized and not to overload the API." false sleep "$sleep_time" fi if ! curl "$url" >"$file"; then - log_info "E: Download of aWATTar prices from '$url' to '$file' failed." + log_message "E: Download of aWATTar prices from '$url' to '$file' failed." exit_with_cleanup 1 fi if ! test -f "$file"; then - log_info "E: Could not get aWATTar prices from '$url' to feed file '$file'." + log_message "E: Could not get aWATTar prices from '$url' to feed file '$file'." exit_with_cleanup 1 fi if [ -n "$DEBUG" ]; then - log_info "D: Download of file '$file' from URL '$url' successful." >&2 + log_message "D: Download of file '$file' from URL '$url' successful." >&2 fi echo >>"$file" awk '/data_price_hour_rel_.*_amount: / {print substr($0, index($0, ":") + 2)}' "$file" >"$output_file" @@ -401,7 +301,7 @@ download_awattar_prices() { if [ -f "$file2" ] && [ "$(wc -l <"$file1")" = "$(wc -l <"$file2")" ]; then rm -f "$file2" - log_info "I: File '$file2' has no tomorrow data, we have to try it again until the new prices are online." false + log_message "I: File '$file2' has no tomorrow data, we have to try it again until the new prices are online." false fi } @@ -425,13 +325,13 @@ download_tibber_prices() { local sleep_time="$3" if [ -z "$DEBUG" ]; then - log_info "I: Please be patient. First we wait $sleep_time seconds in case the system clock is not syncronized and not to overload the API." false + log_message "I: Please be patient. First we wait $sleep_time seconds in case the system clock is not syncronized and not to overload the API." false sleep "$sleep_time" else - log_info "D: No delay of download of Tibber data since DEBUG variable set." + log_message "D: No delay of download of Tibber data since DEBUG variable set." fi if ! get_tibber_api | tr -d '{}[]' >"$file"; then - log_info "E: Download of Tibber prices from '$url' to '$file' failed." + log_message "E: Download of Tibber prices from '$url' to '$file' failed." exit_with_cleanup 1 fi @@ -450,7 +350,7 @@ download_tibber_prices() { echo "date_now_day: $timestamp" >>"$file17" if [ ! -s "$file16" ]; then - log_info "E: Tibber prices cannot be extracted to '$file16', please check your Tibber API Key." + log_message "E: Tibber prices cannot be extracted to '$file16', please check your Tibber API Key." rm "$file" exit_with_cleanup 1 fi @@ -463,99 +363,92 @@ download_entsoe_prices() { local sleep_time="$4" if [ -z "$DEBUG" ]; then - log_info "I: Please be patient. First we wait $sleep_time seconds in case the system clock is not syncronized and not to overload the API." false + log_message "I: Please be patient. First we wait $sleep_time seconds in case the system clock is not syncronized and not to overload the API." sleep "$sleep_time" else - log_info "D: No delay of download of entsoe data since DEBUG variable set." >&2 + log_message "D: No delay of download of entsoe data since DEBUG variable set." >&2 fi if ! curl "$url" >"$file"; then - log_info "E: Retrieval of entsoe data from '$url' into file '$file' failed." + log_message "E: Retrieval of entsoe data from '$url' into file '$file' failed." exit_with_cleanup 1 fi if ! test -f "$file"; then - log_info "E: Could not find file '$file' with entsoe price data. Curl itself reported success." + log_message "E: Could not find file '$file' with entsoe price data. Curl itself reported success." exit_with_cleanup 1 fi - if [ -n "$DEBUG" ]; then log_info "D: No delay of download of entsoe data since DEBUG variable set." >&2 "D: Entsoe file '$file' with price data downloaded" >&2; fi + if [ -n "$DEBUG" ]; then log_message "D: Entsoe file '$file' with price data downloaded" >&2; fi if [ ! -s "$file" ]; then - log_info "E: Entsoe file '$file' is empty, please check your entsoe API Key." + log_message "E: Entsoe file '$file' is empty, please check your entsoe API Key." exit_with_cleanup 1 fi - if [ -n "$DEBUG" ]; then log_info "D: No delay of download of entsoe data since DEBUG variable set." >&2 "D: Entsoe file '$file' with price data downloaded"; fi + if [ -n "$DEBUG" ]; then log_message "D: No delay of download of entsoe data since DEBUG variable set." "D: Entsoe file '$file' with price data downloaded" >&2; fi awk ' - # Capture content inside the tag - // { - capture_period = 1 - } - /<\/Period>/ { - capture_period = 0 - } - # Ensure we are within a valid period and capture prices for one-hour resolution - capture_period && /PT60M<\/resolution>/ { - valid_period = 1 - } - valid_period && // { - gsub("", "", $0) - gsub("<\/price.amount>", "", $0) - gsub(/^[\t ]+|[\t ]+$/, "", $0) - prices = prices $0 ORS - } - valid_period && /<\/Period>/ { - exit - } - - # Capture error information inside the tag - // { - in_reason = 1 - error_message = "" - } - in_reason && // { - gsub(/|<\/code>/, "") - gsub(/^[\t ]+|[\t ]+$/, "", $0) - error_code = $0 - } - in_reason && // { - gsub(/|<\/text>/, "") - gsub(/^[\t ]+|[\t ]+$/, "", $0) - error_message = $0 - } - /<\/Reason>/ { - in_reason = 0 - } - - # At the end of processing, print out the captured prices or any error messages - END { - if (error_code == 999) { - log_info "E: Entsoe data retrieval error:", error_message - exit_with_cleanup 1 - } else if (prices != "") { - printf "%s", prices > "'"$output_file"'" - } else { - if ("'"$output_file"'" != "'"$file13"'") { - log_info "E: No prices found in the today XML data." - exit_with_cleanup 1 - } - } - log_info "E: No prices found in the tomorrow XML data." - } - ' "$file" - +// { + capture_period = 1 +} +/<\/Period>/ { + capture_period = 0 +} +capture_period && /PT60M<\/resolution>/ { + valid_period = 1 +} +valid_period && // { + gsub("", "", $0) + gsub("<\/price.amount>", "", $0) + gsub(/^[\t ]+|[\t ]+$/, "", $0) + prices = prices $0 ORS +} +valid_period && /<\/Period>/ { + exit +} + + +// { + in_reason = 1 + error_message = "" +} + +in_reason && // { + gsub(/|<\/code>/, "") + gsub(/^[\t ]+|[\t ]+$/, "", $0) + error_code = $0 +} + +in_reason && // { + gsub(/|<\/text>/, "") + gsub(/^[\t ]+|[\t ]+$/, "", $0) + error_message = $0 +} + +/<\/Reason>/ { + in_reason = 0 +} + +END { + if (error_code == 999) { + print "E: Entsoe data retrieval error:", error_message + } else if (prices != "") { + printf "%s", prices > "'"$output_file"'" + } else + print "E: No prices found in the XML data." +} +' "$file" + if [ -f "$output_file" ]; then sort -g "$output_file" > "${output_file%.*}_sorted.${output_file##*.}" timestamp=$(TZ=$TZ date +%d) echo "date_now_day: $timestamp" >> "$output_file" - fi - + + # Check if tomorrow file contains next day prices if [ "$include_second_day" = 1 ] && grep -q "PT60M" "$file" && [ "$(wc -l <"$output_file")" -gt 3 ]; then cat $file10 >$file8 - # echo >> $file8 if [ -f "$file13" ]; then cat "$file13" >>"$file8" fi @@ -566,34 +459,36 @@ download_entsoe_prices() { else cp $file11 $file19 # If no second day, copy sorted price file. fi + else exit_with_cleanup 1 + fi } download_solarenergy() { if ((use_solarweather_api_to_abort == 1)); then delay=$((RANDOM % 15 + 1)) if [ -z "$DEBUG" ]; then - log_info "I: Please be patient. A delay of $delay seconds will help avoid overloading the Solarweather-API." false + log_message "I: Please be patient. A delay of $delay seconds will help avoid overloading the Solarweather-API." false # Delaying a random time <=15s to reduce impact on site - download is not time-critical sleep "$delay" else - log_info "D: No delay of download of solarenergy data since DEBUG variable set." >&2 + log_message "D: No delay of download of solarenergy data since DEBUG variable set." >&2 fi if ! curl "$link3" -o "$file3"; then - log_info "E: Download of solarenergy data from '$link3' failed." + log_message "E: Download of solarenergy data from '$link3' failed." exit_with_cleanup 1 elif ! test -f "$file3"; then - log_info "E: Could not get solarenergy data, missing file '$file3'." + log_message "E: Could not get solarenergy data, missing file '$file3'." exit_with_cleanup 1 fi if [ -n "$DEBUG" ]; then - log_info "D: File3 $file3 downloaded" >&2 + log_message "D: File3 $file3 downloaded" >&2 fi if ! test -f "$file3"; then - log_info "E: Could not find downloaded file '$file3' with solarenergy data." + log_message "E: Could not find downloaded file '$file3' with solarenergy data." exit_with_cleanup 1 fi if [ -n "$DEBUG" ]; then - log_info "D: Solarenergy data downloaded to file '$file3'." + log_message "D: Solarenergy data downloaded to file '$file3'." fi fi } @@ -651,7 +546,7 @@ convert_vars_to_integer() { printf -v "$integer_var" '%s' "$(euroToMillicent "${!var}" "$potency")" local value="${!integer_var}" # Speichern Sie den Wert in einer temporären Variable if [ -n "$DEBUG" ]; then - log_info "D: Variable: $var | Original: ${!var} | Integer: $value | Len: ${#value}" >&2 + log_message "D: Variable: $var | Original: ${!var} | Integer: $value | Len: ${#value}" >&2 fi done } @@ -712,10 +607,12 @@ evaluate_conditions() { for condition in "${!conditions_ref[@]}"; do if [ -n "$DEBUG" ]; then - result="( ${descriptions_ref[$condition]} ) evaluates to $([ "${conditions_ref[$condition]}" -eq 1 ] && echo true || echo false)" - log_info "D: condition_evaluation [ $result ]." >&2 + description_value="${descriptions_ref[$condition]}" + condition_evaluation=$([ "${conditions_ref[$condition]}" -eq 1 ] && echo true || echo false) + result="($description_value) evaluates to $condition_evaluation" + log_message "D: condition_evaluation [ $result ]." >&2 fi - + if ((conditions_ref[$condition])) && [[ $condition_met -eq 0 ]]; then execute_ref=1 condition_met_ref="$condition" @@ -746,8 +643,11 @@ is_charging_economical() { [[ $reference_price -ge $total_cost ]] && is_economical=0 if [ -n "$DEBUG" ]; then - log_info "D: is_charging_economical [ $is_economical - $([ "$is_economical" -eq 1 ] && echo "false" || echo "true") ]." >&2 - log_info "D: if [ reference_price ($(millicentToEuro $reference_price)) > total_cost ($(millicentToEuro $total_cost)) ] result is $([ "$is_economical" -eq 1 ] && echo "false" || echo "true")." >&2 + log_message "D: is_charging_economical [ $is_economical - $([ "$is_economical" -eq 1 ] && echo "false" || echo "true") ]." >&2 + reference_price_euro=$(millicentToEuro $reference_price) + total_cost_euro=$(millicentToEuro $total_cost) + is_economical_str=$([ "$is_economical" -eq 1 ] && echo "false" || echo "true") + log_message "D: if [ reference_price $reference_price_euro > total_cost $total_cost_euro ] result is $is_economical_str." >&2 fi return $is_economical @@ -760,10 +660,10 @@ manage_charging() { if [[ $action == "on" ]]; then $charger_command_turnon >/dev/null - log_info "I: Victron scheduled charging is ON. Battery SOC is at $SOC_percent %. $reason" + log_message "I: Victron scheduled charging is ON. Battery SOC is at $SOC_percent %. $reason" else $charger_command_turnoff >/dev/null - log_info "I: Victron scheduled charging is OFF. Battery SOC is at $SOC_percent %. $reason" + log_message "I: Victron scheduled charging is OFF. Battery SOC is at $SOC_percent %. $reason" fi } @@ -773,7 +673,7 @@ check_abort_condition() { local log_message=$2 if ((condition_result)); then - log_info "I: $log_message Abort." + log_message "I: $log_message Abort." execute_charging=0 execute_switchablesockets_on=0 fi @@ -786,12 +686,12 @@ manage_fritz_sockets() { [ "$action" != "off" ] && action=$([ "$execute_switchablesockets_on" == "1" ] && echo "on" || echo "off") if fritz_login; then - log_info "I: Turning $action Fritz sockets." + log_message "I: Turning $action Fritz sockets." for socket in "${sockets[@]}"; do [ "$socket" != "0" ] && manage_fritz_socket "$action" "$socket" done else - log_info "E: Fritz login failed." + log_message "E: Fritz login failed." fi } @@ -799,7 +699,7 @@ manage_fritz_socket() { local action=$1 local socket=$2 local url="http://$fbox/webservices/homeautoswitch.lua?sid=$sid&ain=$socket&switchcmd=setswitch$action" - curl -s "$url" >/dev/null || log_info "E: Could not call URL '$url' to switch $action said switch - ignored." + curl -s "$url" >/dev/null || log_message "E: Could not call URL '$url' to switch $action said switch - ignored." } fritz_login() { @@ -807,7 +707,7 @@ fritz_login() { sid="" challenge=$(curl -s "http://$fbox/login_sid.lua" | grep -o "[a-z0-9]\{8\}" | cut -d'>' -f 2) if [ -z "$challenge" ]; then - log_info "E: Could not retrieve challenge from login_sid.lua." + log_message "E: Could not retrieve challenge from login_sid.lua." return 1 fi @@ -816,12 +716,12 @@ fritz_login() { grep -o "[a-z0-9]\{16\}" | cut -d'>' -f 2) if [ "$sid" = "0000000000000000" ]; then - log_info "E: Login to Fritz!Box failed." + log_message "E: Login to Fritz!Box failed." return 1 fi if [ -n "$DEBUG" ]; then - log_info "D: Login to Fritz!Box successful." >&2 + log_message "D: Login to Fritz!Box successful." >&2 fi return 0 } @@ -832,7 +732,7 @@ manage_shelly_sockets() { [ "$action" != "off" ] && action=$([ "$execute_switchablesockets_on" == "1" ] && echo "on" || echo "off") - log_info "I: Turning $action Shelly sockets." + log_message "I: Turning $action Shelly sockets." for ip in "${shelly_ips[@]}"; do [ "$ip" != "0" ] && manage_shelly_socket "$action" "$ip" done @@ -841,7 +741,7 @@ manage_shelly_sockets() { manage_shelly_socket() { local action=$1 local ip=$2 - curl -s -u "$shellyuser:$shellypasswd" "http://$ip/relay/0?turn=$action" -o /dev/null || log_info "E: Could not execute switch-$action of Shelly socket with IP $ip - ignored." + curl -s -u "$shellyuser:$shellypasswd" "http://$ip/relay/0?turn=$action" -o /dev/null || log_message "E: Could not execute switch-$action of Shelly socket with IP $ip - ignored." } millicentToEuro() { @@ -872,16 +772,12 @@ euroToMillicent() { # Replace each comma with a period, fixme if this is wrong euro=$(echo "$euro" | sed 's/,/./g') - if which bc >/dev/null 2>&1; then - # Using bc to multiply the euro number and convert it to an integer - v=$(echo "scale=0; $euro * 10^$potency / 1" | bc) - else - v=$(awk "BEGIN {print int($euro * (10 ^ $potency))}") - fi + # v=$(awk "BEGIN {print int($euro * (10 ^ $potency))}") + v=$(awk -v euro="$euro" -v potency="$potency" 'BEGIN {printf "%.0f", euro * (10 ^ potency)}') if [ -z "$v" ]; then - log_info "E: Could not translate '$euro' to an integer." - log_info "E: Called from ${FUNCNAME[1]} at line ${BASH_LINENO[0]}" + log_message "E: Could not translate '$euro' to an integer." + log_message "E: Called from ${FUNCNAME[1]} at line ${BASH_LINENO[0]}" return 1 fi echo "$v" @@ -889,40 +785,42 @@ euroToMillicent() { } euroToMillicent_test() { - log_info "I: Testing euroToMillicent" false + log_message "I: Testing euroToMillicent" false for i in 123456 12345.6 1234.56 123.456 12.3456 1.23456 0.123456 .123456 .233 .23 .2 2.33 2.3 2 2,33 2,3 2 23; do echo -n "$i -> " euroToMillicent $i done } -log_info() { +log_message() { local msg="$1" - local prefix=$(echo "$msg" | head -n 1 | cut -d' ' -f1) # Extract the first word from the first line - local color="\033[1m" # Default color - local writeToLog=true # Default is true + local prefix=$(echo "$msg" | head -n 1 | cut -d' ' -f1) # Extract the first word from the first line + local color="\033[1m" # Default color + local writeToLog=true # Default is true case "$prefix" in - "E:") color="\033[1;31m" ;; # Bright Red - "D:") color="\033[1;34m" # Bright Blue - writeToLog=false ;; # Default to not log debug messages - "W:") color="\033[1;33m" ;; # Bright Yellow - "I:") color="\033[1;32m" ;; # Bright Green + "E:") color="\033[1;31m" ;; # Bright Red + "D:") + color="\033[1;34m" # Bright Blue + writeToLog=false + ;; # Default to not log debug messages + "W:") color="\033[1;33m" ;; # Bright Yellow + "I:") color="\033[1;32m" ;; # Bright Green esac - writeToLog="${2:-$writeToLog}" # Override default if second parameter is provided + writeToLog="${2:-$writeToLog}" # Override default if second parameter is provided # Print to console with color codes printf "${color}%b\033[0m\n" "$msg" # If we should write to the log, write without color codes if [ "$writeToLog" == "true" ]; then - echo -e "$msg" | sed 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE" + echo -e "$msg" | sed 's/\x1b\[[0-9;]*m//g' >>"$LOG_FILE" fi } exit_with_cleanup() { - log_info "I: Cleanup and exit with error $1" + log_message "I: Cleanup and exit with error $1" manage_charging "off" "Turn off charging." manage_fritz_sockets "off" manage_shelly_sockets "off" @@ -933,11 +831,128 @@ exit_with_cleanup() { ### Begin of the script... ### #################################### +# Path to the current script directory +DIR="$(dirname "$0")" + +if [ -f "$DIR/config.txt" ]; then + # Include the configuration file + source "$DIR/config.txt" +else + log_message "E: The file $DIR/config.txt was not found! Configure the existing sample.config.txt file and then save it as config.txt in the same directory." false + exit 127 +fi + +if [ -z "$UNAME" ]; then + UNAME=$(uname) +fi +if [ "Darwin" = "$UNAME" ]; then + log_message "W: MacOS has a different implementation of 'date' - use conda if hunting a bug on a mac". +fi + +# further API parameters (no need to edit) +dateInSeconds=$(LC_ALL=C TZ=$TZ date +"%s") +if [ "Darwin" = "$UNAME" ]; then + yesterday=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds - 86400)) +%d)2300 + yestermonth=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds - 86400)) +%m) + yesteryear=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds - 86400)) +%Y) + today=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%d)2300 + today2=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%d) + todaymonth=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%m) + todayyear=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%Y) + tomorrow=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%d)2300 + tomorrow2=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%d) + tomorrowmonth=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%m) + tomorrowyear=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds + 86400)) +%Y) + getnow=$(LC_ALL=C TZ=$TZ date -j -f "%s" $((dateInSeconds)) +%k) +else + yesterday=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds - 86400)) +%d)2300 + yestermonth=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds - 86400)) +%m) + yesteryear=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds - 86400)) +%Y) + today=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%d)2300 + today2=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%d) + todaymonth=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%m) + todayyear=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%Y) + tomorrow=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%d)2300 + tomorrow2=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%d) + tomorrowmonth=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%m) + tomorrowyear=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds + 86400)) +%Y) + getnow=$(LC_ALL=C TZ=$TZ date -d @$((dateInSeconds)) +%k) +fi + +now_linenumber=$((getnow + 1)) +link1="https://api.awattar.$awattar/v1/marketdata/current.yaml" +link2="http://api.awattar.$awattar/v1/marketdata/current.yaml?tomorrow=include" +link3="https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/$latitude%2C%20$longitude/$todayyear-$todaymonth-$today2/$tomorrowyear-$tomorrowmonth-$tomorrow2?unitGroup=metric&elements=solarenergy%2Ccloudcover%2Csunrise%2Csunset&include=days&key=$visualcrossing_api_key&contentType=csv" +link4="https://web-api.tp.entsoe.eu/api?securityToken=$entsoe_eu_api_security_token&documentType=A44&in_Domain=$in_Domain&out_Domain=$out_Domain&periodStart=$yesteryear$yestermonth$yesterday&periodEnd=$todayyear$todaymonth$today" +link5="https://web-api.tp.entsoe.eu/api?securityToken=$entsoe_eu_api_security_token&documentType=A44&in_Domain=$in_Domain&out_Domain=$out_Domain&periodStart=$todayyear$todaymonth$today&periodEnd=$tomorrowyear$tomorrowmonth$tomorrow" +link6="https://api.tibber.com/v1-beta/gql" +file1=/tmp/awattar_today_prices.yaml +file2=/tmp/awattar_tomorrow_prices.yaml +file3=/tmp/expected_solarenergy.csv +file4=/tmp/entsoe_today_prices.xml +file5=/tmp/entsoe_tomorrow_prices.xml +file6=/tmp/awattar_prices.txt +file7=/tmp/awattar_prices_sorted.txt +file8=/tmp/entsoe_prices.txt +file9=/tmp/entsoe_tomorrow_prices_sorted.txt +file10=/tmp/entsoe_today_prices.txt +file11=/tmp/entsoe_today_prices_sorted.txt +file12=/tmp/tibber_prices_sorted.txt +file13=/tmp/entsoe_tomorrow_prices.txt +file14=/tmp/tibber_prices.txt +file15=/tmp/tibber_today_prices.txt +file16=/tmp/tibber_today_prices_sorted.txt +file17=/tmp/tibber_tomorrow_prices.txt +file18=/tmp/tibber_tomorrow_prices_sorted.txt +file19=/tmp/entsoe_prices_sorted.txt + +########## Optional environmental variables + +if [ -z "$LOG_FILE" ]; then + LOG_FILE="/tmp/spotmarket-switcher.log" +fi +if [ -z "$LOG_MAX_SIZE" ]; then + LOG_MAX_SIZE=1024 # 1 MB +fi +if [ -z "$LOG_FILES_TO_KEEP" ]; then + LOG_FILES_TO_KEEP=2 +fi + +########## Testing series of preconditions prior to execution of script + +num_tools_missing=0 +tools="awk curl cat sed sort head tail" +if [ 0 -lt $use_victron_charger ]; then + tools="$tools dbus" + charger_command_turnon="dbus -y com.victronenergy.settings /Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day SetValue -- 7" + charger_command_turnoff="dbus -y com.victronenergy.settings /Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day SetValue -- -7" + SOC_percent=$(dbus-send --system --print-reply --dest=com.victronenergy.system /Dc/Battery/Soc com.victronenergy.BusItem.GetValue | grep variant | awk '{print $3}') # This will get the battery state of charge (SOC) from a Victron Energy system +fi + +for tool in $tools; do + if ! which "$tool" >/dev/null; then + log_message "E: Please ensure the tool '$tool' is found." + num_tools_missing=$((num_tools_missing + 1)) + fi +done + +if [ $num_tools_missing -gt 0 ]; then + log_message "E: $num_tools_missing tools are missing." + exit 127 +fi + +unset num_tools_missing + +########## Start ########## + echo >>"$LOG_FILE" +log_message "I: Bash Version: $(bash --version | head -n 1)" +log_message "I: Spotmarket-Switcher - Version $VERSION" + parse_and_validate_config "$DIR/config.txt" # if [ $? -eq 1 ]; then - # Handle error +# Handle error # fi # An independent segment to test the conversion of floats to integers @@ -952,14 +967,14 @@ if ((select_pricing_api == 1)); then # Test if data is current get_current_awattar_day if [ "$current_awattar_day" = "$(TZ=$TZ date +%-d)" ]; then - log_info "I: aWATTar today-data is up to date." false + log_message "I: aWATTar today-data is up to date." false else - log_info "I: aWATTar today-data is outdated, fetching new data." false + log_message "I: aWATTar today-data is outdated, fetching new data." false rm -f $file1 $file6 $file7 download_awattar_prices "$link1" "$file1" "$file6" $((RANDOM % 21 + 10)) fi else # Data file1 does not exist - log_info "I: Fetching today-data data from aWATTar." false + log_message "I: Fetching today-data data from aWATTar." false download_awattar_prices "$link1" "$file1" "$file6" $((RANDOM % 21 + 10)) fi @@ -969,14 +984,14 @@ elif ((select_pricing_api == 2)); then # Test if data is current get_current_entsoe_day if [ "$current_entsoe_day" = "$(TZ=$TZ date +%d)" ]; then - log_info "I: Entsoe today-data is up to date." false + log_message "I: Entsoe today-data is up to date." false else - log_info "I: Entsoe today-data is outdated, fetching new data." false + log_message "I: Entsoe today-data is outdated, fetching new data." false rm -f "$file4" "$file5" "$file8" "$file9" "$file10" "$file11" "$file13" "$file19" download_entsoe_prices "$link4" "$file4" "$file10" $((RANDOM % 21 + 10)) fi else # Entsoe data does not exist - log_info "I: Fetching today-data data from Entsoe." false + log_message "I: Fetching today-data data from Entsoe." false download_entsoe_prices "$link4" "$file4" "$file10" $((RANDOM % 21 + 10)) fi @@ -987,14 +1002,14 @@ elif ((select_pricing_api == 3)); then # Test if data is current get_current_tibber_day if [ "$current_tibber_day" = "$(TZ=$TZ date +%d)" ]; then - log_info "I: Tibber today-data is up to date." false + log_message "I: Tibber today-data is up to date." false else - log_info "I: Tibber today-data is outdated, fetching new data." false + log_message "I: Tibber today-data is outdated, fetching new data." false rm -f "$file14" "$file15" "$file16" download_tibber_prices "$link6" "$file14" $((RANDOM % 21 + 10)) fi else # Tibber data does not exist - log_info "I: Fetching today-data data from Tibber." false + log_message "I: Fetching today-data data from Tibber." false download_tibber_prices "$link6" "$file14" $((RANDOM % 21 + 10)) fi fi @@ -1008,14 +1023,14 @@ if ((include_second_day == 1)); then # Test if data is current get_current_awattar_day2 if [ "$current_awattar_day2" = "$(TZ=$TZ date +%-d)" ]; then - log_info "I: aWATTar tomorrow-data is up to date." false + log_message "I: aWATTar tomorrow-data is up to date." false else - log_info "I: aWATTar tomorrow-data is outdated, fetching new data." false + log_message "I: aWATTar tomorrow-data is outdated, fetching new data." false rm -f $file3 download_awattar_prices "$link2" "$file2" "$file6" $((RANDOM % 21 + 10)) fi else # Data file2 does not exist - log_info "I: aWATTar tomorrow-data does not exist, fetching data." false + log_message "I: aWATTar tomorrow-data does not exist, fetching data." false download_awattar_prices "$link2" "$file2" "$file6" $((RANDOM % 21 + 10)) fi @@ -1023,7 +1038,7 @@ if ((include_second_day == 1)); then # Test if Entsoe tomorrow data exists if [ ! -s "$file9" ]; then - log_info "I: File '$file9' has no tomorrow data, we have to try it again until the new prices are online." false + log_message "I: File '$file9' has no tomorrow data, we have to try it again until the new prices are online." false rm -f "$file5" "$file9" "$file13" download_entsoe_prices "$link5" "$file5" "$file13" $((RANDOM % 21 + 10)) fi @@ -1032,7 +1047,7 @@ if ((include_second_day == 1)); then if [ ! -s "$file18" ]; then rm -f "$file17" "$file18" - log_info "I: File '$file18' has no tomorrow data, we have to try it again until the new prices are online." false + log_message "I: File '$file18' has no tomorrow data, we have to try it again until the new prices are online." false rm -f "$file12" "$file14" "$file15" "$file16" "$file17" download_tibber_prices "$link6" "$file14" $((RANDOM % 21 + 10)) sort -t, -k1.9n $file17 >>"$file12" @@ -1067,26 +1082,28 @@ if ((use_solarweather_api_to_abort == 1)); then get_suntime_today fi -log_info "I: Please verify correct system time and timezone:\n $(TZ=$TZ date)" +log_message "I: Please verify correct system time and timezone:\n $(TZ=$TZ date)" echo -log_info "I: Current price is $current_price $Unit." -log_info "I: Lowest price will be $lowest_price $Unit." false -log_info "I: The average price will be $average_price $Unit." false -log_info "I: Highest price will be $highest_price $Unit." false -log_info "I: Second lowest price will be $second_lowest_price $Unit." false -log_info "I: Third lowest price will be $third_lowest_price $Unit." false -log_info "I: Fourth lowest price will be $fourth_lowest_price $Unit." false -log_info "I: Fifth lowest price will be $fifth_lowest_price $Unit." false -log_info "I: Sixth lowest price will be $sixth_lowest_price $Unit." false +log_message "I: Current price is $current_price $Unit." +log_message "I: Lowest price will be $lowest_price $Unit." false +log_message "I: The average price will be $average_price $Unit." false +log_message "I: Highest price will be $highest_price $Unit." false +log_message "I: Second lowest price will be $second_lowest_price $Unit." false +log_message "I: Third lowest price will be $third_lowest_price $Unit." false +log_message "I: Fourth lowest price will be $fourth_lowest_price $Unit." false +log_message "I: Fifth lowest price will be $fifth_lowest_price $Unit." false +log_message "I: Sixth lowest price will be $sixth_lowest_price $Unit." false if ((use_solarweather_api_to_abort == 1)); then - log_info "I: Sunrise today will be $sunrise_today and sunset will be $sunset_today. Suntime will be $suntime_today minutes." - log_info "I: Solarenergy today will be $solarenergy_today megajoule per sqaremeter with $cloudcover_today percent clouds." - log_info "I: Solarenergy tomorrow will be $solarenergy_tomorrow megajoule per squaremeter with $cloudcover_tomorrow percent clouds." + log_message "I: Sunrise today will be $sunrise_today and sunset will be $sunset_today. Suntime will be $suntime_today minutes." + log_message "I: Solarenergy today will be $solarenergy_today megajoule per sqaremeter with $cloudcover_today percent clouds." + log_message "I: Solarenergy tomorrow will be $solarenergy_tomorrow megajoule per squaremeter with $cloudcover_tomorrow percent clouds." if [ ! -s $file3 ]; then - log_info "E: File '$file3' is empty, please check your API Key if download is still not possible tomorrow." + log_message "E: File '$file3' is empty, please check your API Key if download is still not possible tomorrow." fi find "$file3" -size 0 -delete # FIXME - looks wrong and complicated - simple RM included in prior if clause? +else + log_message "W: skip Solarweather. not activated" fi charging_condition_met="" @@ -1173,15 +1190,21 @@ if ((execute_charging == 1 && use_victron_charger == 1)); then fi elif ((execute_charging != 1 && use_victron_charger == 1)); then manage_charging "off" "Charging was not executed." +else + log_message "W: skip Victron Charger. not activated" fi # Execute Fritz DECT on command if ((use_fritz_dect_sockets == 1)); then manage_fritz_sockets +else + log_message "W: skip Fritz DECT. not activated" fi if ((use_shelly_wlan_sockets == 1)); then manage_shelly_sockets +else + log_message "W: skip Shelly Api. not activated" fi echo >>"$LOG_FILE" @@ -1189,6 +1212,7 @@ echo >>"$LOG_FILE" # Rotating log files if [ -f "$LOG_FILE" ]; then if [ "$(du -k "$LOG_FILE" | awk '{print $1}')" -gt "$LOG_MAX_SIZE" ]; then + log_message "I: Rotating log files" mv "$LOG_FILE" "${LOG_FILE}.$(date +%Y%m%d%H%M%S)" touch "$LOG_FILE" find . -maxdepth 1 -name "${LOG_FILE}*" -type f -exec ls -1t {} + | @@ -1199,5 +1223,5 @@ if [ -f "$LOG_FILE" ]; then fi if [ -n "$DEBUG" ]; then - log_info "D: [ OK ]" >&2 + log_message "D: \[ OK \]" >&2 fi diff --git a/scripts/run b/scripts/run index 82a2441..696cf44 100755 --- a/scripts/run +++ b/scripts/run @@ -1,6 +1,7 @@ -#!/bin/sh +#!/bin/bash -License=$(cat < "$rc_local_file" + echo "#!/bin/sh" >"$rc_local_file" chmod +x "$rc_local_file" - $code fi # Check if the code is already in rc.local, if not, add it if ! grep -qF "$code" "$rc_local_file"; then - echo "$code" >> "$rc_local_file" - $code + { + echo '(crontab -l | grep -Fxq "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh") || (crontab -l; echo "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh")' + (crontab -l | grep -Fxq "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh") || ( + crontab -l + echo "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh" + ) | crontab - + } | tee -a "$rc_local_file" fi # Display a success message in DEBUG mode diff --git a/victron-venus-os-install.sh b/victron-venus-os-install.sh index 0b70cc0..de4caa1 100755 --- a/victron-venus-os-install.sh +++ b/victron-venus-os-install.sh @@ -1,7 +1,7 @@ -#!/bin/sh +#!/bin/bash License=$( - cat </dev/null; then - missing="$missing $tool" - fi + if ! which "$tool" >/dev/null; then + missing="$missing $tool" + fi done if [ -n "$missing" ]; then - e_error "E: Install the following tools prior to running this install script or the installed scripts: $missing" - exit 1 + e_error "E: Install the following tools prior to running this install script or the installed scripts: $missing" + exit 1 fi for tool in wget curl; do - if ! which "$tool" >/dev/null; then - missing="$missing $tool" - fi + if ! which "$tool" >/dev/null; then + missing="$missing $tool" + fi done if [ -n "$missing" ]; then - e_note "W: Install the following tools prior to the execution of the installed scripts: $missing." - e_note " Try running 'opkg install $missing'." - echo - e_note " Now continuing with the installation, which will be fine per se, but you as the user are responsible to get those dependencies installed to prevent the control script from failing. Drop an issue at https://github.com/christian1980nrw/Spotmarket-Switcher/issues if this package shall somehow prepare you better." - echo + e_note "W: Install the following tools prior to the execution of the installed scripts: $missing." + e_note " Try running 'opkg install $missing'." + echo + e_note " Now continuing with the installation, which will be fine per se, but you as the user are responsible to get those dependencies installed to prevent the control script from failing. Drop an issue at https://github.com/christian1980nrw/Spotmarket-Switcher/issues if this package shall somehow prepare you better." + echo fi # DESTDIR is optionally set as an environment variable. if [ -n "$DESTDIR" ] && [ "/" != "$DESTDIR" ]; then - e_note "W: The environment variable DESTDIR is set to the value '$DESTDIR' that is different from '/', the root directory." - e_note " This is meant to support testing and packaging, not for a true installation." - e_underline " If you are using Victron Venus OS, the correct installation directory should be '/'." - e_note " No harm is expected to be caused, but it's recommended to install directly to '/' for a standard installation." - e_note " You can cancel now with CTRL-C if this is not what you intended." - sleep 5 - e_underline "I: Will now continue. You can still interrupt at any time." - echo + e_note "W: The environment variable DESTDIR is set to the value '$DESTDIR' that is different from '/', the root directory." + e_note " This is meant to support testing and packaging, not for a true installation." + e_underline " If you are using Victron Venus OS, the correct installation directory should be '/'." + e_note " No harm is expected to be caused, but it's recommended to install directly to '/' for a standard installation." + e_note " You can cancel now with CTRL-C if this is not what you intended." + sleep 5 + e_underline "I: Will now continue. You can still interrupt at any time." + echo else - ln -s /data/etc/Spotmarket-Switcher/service /service/Spotmarket-Switcher - (crontab -l | grep -Fxq "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh") || ( - crontab -l - echo "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh" - ) | crontab - + ln -s /data/etc/Spotmarket-Switcher/service /service/Spotmarket-Switcher + (crontab -l | grep -Fxq "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh") || ( + crontab -l + echo "0 * * * * /data/etc/Spotmarket-Switcher/controller.sh" + ) | crontab - fi if ! mkdir -p "$DESTDIR"/data/etc/Spotmarket-Switcher/service; then - e_error "E: Could not create service directory '$DESTDIR/data/etc/Spotmarket-Switcher/service'." - exit 1 + e_error "E: Could not create service directory '$DESTDIR/data/etc/Spotmarket-Switcher/service'." + exit 1 fi downloadToDest() { - url="$1" - dest="$2" - - echo "I: Downloading '$(basename "$url")'" - if ! wget --no-verbose --continue --no-directories --show-progress -O "$dest" "$url"; then - e_error "E: Download of '$(basename "$url")' failed." - return 1 - fi - chmod +x "$dest" + url="$1" + dest="$2" + + echo "I: Downloading '$(basename "$url")'" + if ! wget --no-verbose --continue --no-directories --show-progress -O "$dest" "$url"; then + e_error "E: Download of '$(basename "$url")' failed." + return 1 + fi + chmod +x "$dest" } download_file_if_missing() { - local file_path="$1" - local dest_path="$2" - local file_url="$3" - - if [ -x "$file_path" ]; then - cp "$file_path" "$dest_path" - else - if [ -n "$DEBUG" ]; then - echo "D: ls \$SRCDIR" - ls "$SRCDIR" || { - echo "D: pwd: $(pwd)" - ls - } - fi - e_note "I: Downloading '$(basename "$file_path")' from github repository - '$BRANCH' branch" - downloadToDest "$file_url" "$dest_path" - fi + local file_path="$1" + local dest_path="$2" + local file_url="$3" + + if [ -x "$file_path" ]; then + cp "$file_path" "$dest_path" + else + if [ -n "$DEBUG" ]; then + echo "D: ls \$SRCDIR" + ls "$SRCDIR" || { + echo "D: pwd: $(pwd)" + ls + } + fi + e_note "I: Downloading '$(basename "$file_path")' from github repository - '$BRANCH' branch" + downloadToDest "$file_url" "$dest_path" + fi } if [ -z "$SRCDIR" ]; then - SRCDIR=scripts + SRCDIR=scripts fi if [ -z "$branch" ]; then - BRANCH=main + BRANCH=main fi download_file_if_missing "$SRCDIR/controller.sh" "$DESTDIR/data/etc/Spotmarket-Switcher/controller.sh" https://raw.githubusercontent.com/christian1980nrw/Spotmarket-Switcher/"$BRANCH"/scripts/controller.sh @@ -227,31 +235,31 @@ cp -n "$DESTDIR/data/etc/Spotmarket-Switcher/sample.config.txt" "$DESTDIR/data/e # $DESTDIR is always an absolut path if [ ! -d "$DESTDIR"/service ]; then - if [ -n "$DESTDIR" ] && [ "/" != "$DESTDIR" ]; then - e_note "I: The '$DESTDIR/service' directory is not existing, as expected because of the custom DESTDIR setting." - e_note " Skipping creation of symbolic link to the Sportmarket-Switcher to register this service." - else - e_note "W: The '$DESTDIR/service' directory is not existing." - e_note " Not installing a symbolic link to the Sportmarket-Switcher to register this service." - e_note " Check on https://github.com/christian1980nrw/Spotmarket-Switcher/issues if that has already been reported." - fi + if [ -n "$DESTDIR" ] && [ "/" != "$DESTDIR" ]; then + e_note "I: The '$DESTDIR/service' directory is not existing, as expected because of the custom DESTDIR setting." + e_note " Skipping creation of symbolic link to the Sportmarket-Switcher to register this service." + else + e_note "W: The '$DESTDIR/service' directory is not existing." + e_note " Not installing a symbolic link to the Sportmarket-Switcher to register this service." + e_note " Check on https://github.com/christian1980nrw/Spotmarket-Switcher/issues if that has already been reported." + fi else - if [ ! -L "$DESTDIR"/service/Spotmarket-Switcher ]; then - ln -s "$DESTDIR"/data/etc/Spotmarket-Switcher/service "$DESTDIR"/service/Spotmarket-Switcher - fi + if [ ! -L "$DESTDIR"/service/Spotmarket-Switcher ]; then + ln -s "$DESTDIR"/data/etc/Spotmarket-Switcher/service "$DESTDIR"/service/Spotmarket-Switcher + fi fi if [ -e "$DESTDIR"/data/rc.local ]; then - if grep -q "Spotmarket-Switcher/service /service/Spotmarket-Switcher" "$DESTDIR"/data/rc.local; then - e_note "I: Spotmarket-Switcher/service is already known to rc.local boot script - not added again." - else - e_note "I: Adding link to Spotmarket-Switcher/service to rc.local boot script." - sed -i '1s|^|ln -s /data/etc/Spotmarket-Switcher/service /service/Spotmarket-Switcher\n|' /data/rc.local - fi + if grep -q "Spotmarket-Switcher/service /service/Spotmarket-Switcher" "$DESTDIR"/data/rc.local; then + e_note "I: Spotmarket-Switcher/service is already known to rc.local boot script - not added again." + else + e_note "I: Adding link to Spotmarket-Switcher/service to rc.local boot script." + sed -i '1s|^|ln -s /data/etc/Spotmarket-Switcher/service /service/Spotmarket-Switcher\n|' /data/rc.local + fi else - e_note "I: Creating new data/rc.local boot script" - echo "ln -s /data/etc/Spotmarket-Switcher/service /service/Spotmarket-Switcher" >"$DESTDIR"/data/rc.local - chmod +x "$DESTDIR"/data/rc.local + e_note "I: Creating new data/rc.local boot script" + echo "ln -s /data/etc/Spotmarket-Switcher/service /service/Spotmarket-Switcher" >"$DESTDIR"/data/rc.local + chmod +x "$DESTDIR"/data/rc.local fi echo @@ -266,6 +274,6 @@ echo e_note "Note: This installation will survive a Venus OS firmware update." echo if [ -n "$missing" ]; then - e_note "Note: Remember to install these missing executables: $missing" - echo + e_note "Note: Remember to install these missing executables: $missing" + echo fi