pfSense - Turn off network when electricity price hits threshold.

This is a script that you can add as a cron job in pfSense to disable networking when the electricity price hits a threshold level. It's for Swedish prices, but you can modify accordingly - as long as you can get prices in json format. When the price is under the threshold, the network will start again. 

#!/bin/sh

# Configuration
THRESHOLD=0.2                 # SEK/kWh
BLOCK_IP="192.168.2.71"       # IP to block
PRICE_ZONE="SE2"              # SE2=Sydöstra Sverige
LOG_TAG="energy_blocker"       # Syslog identifier
LOOKAHEAD_MINUTES=10           # Check next hour's price this many minutes before hour change

# Absolute paths
CURL="/usr/local/bin/curl"
JQ="/usr/local/bin/jq"
DATE="/bin/date"
PFCTL="/sbin/pfctl"
LOGGER="/usr/bin/logger"
BC="/usr/bin/bc"
GREP="/usr/bin/grep"

echo "[$($DATE '+%Y-%m-%d %H:%M:%S')] Starting price check (SE2) with ${LOOKAHEAD_MINUTES}min lookahead"

# Calculate target hour (current hour +1 with modulo 24)
CURRENT_HOUR=$($DATE +%H)
TARGET_HOUR=$(echo "($CURRENT_HOUR + 1) % 24" | $BC)
echo "Checking price for next hour: $TARGET_HOUR:00"

# Handle date rollover at midnight
if [ "$TARGET_HOUR" -eq 0 ]; then
    YEAR=$($DATE -v+1d +%Y)
    MONTH_DAY=$($DATE -v+1d +%m-%d)
else
    YEAR=$($DATE +%Y)
    MONTH_DAY=$($DATE +%m-%d)
fi

# API URL construction
API_URL="https://www.elprisetjustnu.se/api/v1/prices/${YEAR}/${MONTH_DAY}_${PRICE_ZONE}.json"
echo "Fetching price data from: $API_URL"

# Fetch and parse price data
CURRENT_PRICE=$($CURL -sf "$API_URL" | $JQ -r ".[$TARGET_HOUR].SEK_per_kWh")
echo "Next hour price: $CURRENT_PRICE SEK/kWh"

# Validate price data
if [ -z "$CURRENT_PRICE" ] || [ "$CURRENT_PRICE" = "null" ]; then
    echo "ERROR: Invalid price data received"
    $LOGGER -t $LOG_TAG "ERROR: Price check failed for SE2"
    exit 1
fi

# Check current block status
$PFCTL -t blocklist -T test "$BLOCK_IP" >/dev/null 2>&1
WAS_BLOCKED=$?
echo "Current block status for $BLOCK_IP: $([ $WAS_BLOCKED -eq 0 ] && echo "BLOCKED" || echo "UNBLOCKED")"

STATE_CHANGE=0
PRICE_CHECK=$(echo "$CURRENT_PRICE > $THRESHOLD" | $BC -l)
echo "Price comparison result ($CURRENT_PRICE > $THRESHOLD): $PRICE_CHECK"

if [ "$PRICE_CHECK" -eq 1 ]; then
    echo "Next hour price exceeds threshold - checking block status..."
    if [ "$WAS_BLOCKED" -ne 0 ]; then
        echo "IP not blocked - initiating early block procedure"
        $PFCTL -t blocklist -T add "$BLOCK_IP" && \
        $PFCTL -k "$BLOCK_IP"
        $LOGGER -t $LOG_TAG "BLOCKED $BLOCK_IP - Next Hour Price: ${CURRENT_PRICE} SEK/kWh"
        STATE_CHANGE=1
        echo "Successfully blocked $BLOCK_IP 10 minutes early"
    else
        echo "IP already blocked - maintaining block"
    fi
else
    echo "Next hour price below threshold - checking unblock conditions..."
    if [ "$WAS_BLOCKED" -eq 0 ]; then
        echo "IP is blocked - initiating unblock procedure"
        $PFCTL -t blocklist -T delete "$BLOCK_IP" && \
        $PFCTL -k "$BLOCK_IP"
        $LOGGER -t $LOG_TAG "UNBLOCKED $BLOCK_IP - Next Hour Price: ${CURRENT_PRICE} SEK/kWh"
        STATE_CHANGE=1
        echo "Successfully unblocked $BLOCK_IP"
    else
        echo "IP already unblocked - no action needed"
    fi
fi

if [ "$STATE_CHANGE" -eq 1 ]; then    
echo "State changed - verifying persistent rules"
    if ! $PFCTL -s rules | $GREP -q "blocklist"; then
        echo "Adding persistent blocklist rule"
        echo "block in quick from <blocklist> to any" >> /etc/pf.blocklist.conf
        $PFCTL -f /etc/pf.blocklist.conf
    else
        echo "Persistent rule already exists"
    fi
else
    echo "No state change - skipping persistent rule check"
fi

echo "[$($DATE '+%Y-%m-%d %H:%M:%S')] Script execution completed"
exit 0
 
 

Additional requirements; "pgk add jq" from shell and "cron" from pfSense GUI packages.  


Kommentarer