#!/bin/bash P1_STATUS=`mosquitto_sub -t domoctopus/p1/status -C 1` SB40_IP='192.168.1.126' SI60_IP='192.168.1.134' # test max amp at 25A, shouldn't be too limited, but it is easily reached MAX_AMP=32 #MAX_AMP=16 #MAX_AMP=15 TIME=`date "+%s"` SOLAR_POWER=`mbpoll $SB40_IP -a 3 -B -0 -r 30777 -q -1 -c 1 -t 3:int | grep -e 30777 | cut -f 2` function modbus_read() { mbpoll $SI60_IP -a 3 -B -0 -r $1 -q -1 -c 1 -t 3:int | grep -e $1 | cut -f 2 } function modbus_read_fix() { TMP=`modbus_read $1` echo "scale=$2; $TMP/10^$2" | bc } . ./db.credentials #COMMAND=`./readcommand.sh` COMMAND=`mariadb -B --skip-column-names --user=$USERNAME --password=$PASSWORD stroom << EOQ SELECT IFNULL(GROUP_CONCAT(commands.command), 'IDLE') FROM commands AS next_commands JOIN commands ON next_commands.prev_command_id = commands.command_id WHERE commands.command_start <= $TIME AND next_commands.command_start > $TIME EOQ` PRICE=`mariadb -B --skip-column-names --user=$USERNAME --password=$PASSWORD stroom << EOQ SELECT ROUND(1000*ROUND((100+btw_percent)*(epex_price+fee_per_kwh+tax_per_kwh), 3), 0) FROM ( SELECT commands.command_id, commands.prev_command_id, commands.command, prev_commands.command_start prev_command_start, commands.command_start, next_commands.command_start next_command_start FROM commands LEFT JOIN commands AS prev_commands ON prev_commands.command_id = commands.prev_command_id LEFT JOIN commands AS next_commands ON next_commands.prev_command_id = commands.command_id WHERE commands.command_start <= UNIX_TIMESTAMP() AND next_commands.command_start > UNIX_TIMESTAMP() ) AS tmp LEFT JOIN epex ON epex_start >= command_start AND epex_start < next_command_start JOIN ( SELECT tax.tax_per_kwh, tax.tax_start, next_tax.tax_start tax_end FROM tax JOIN tax AS next_tax ON next_tax.prev_tax_id = tax.tax_id ) AS ebal ON tax_start <= epex_start AND tax_end > epex_start JOIN ( SELECT fee.fee_per_kwh, fee.fee_start, next_fee.fee_start fee_end FROM fee JOIN fee AS next_fee ON next_fee.prev_fee_id = fee.fee_id ) AS efee ON fee_start <= epex_start AND fee_end > epex_start JOIN ( SELECT btw.btw_percent, btw.btw_start, next_btw.btw_start btw_end FROM btw JOIN btw AS next_btw ON next_btw.prev_btw_id = btw.btw_id ) AS ebtw ON btw_start <= epex_start AND btw_end > epex_start EOQ ` PRICE_HUMAN=`echo "scale=3; $PRICE/1000" | bc` echo Price $PRICE_HUMAN ct/kWh if [ "$COMMAND" != "IDLE" -a "$COMMAND" != "CHARGE" -a "$COMMAND" != "DISCHARGE" -a "$COMMAND" != "ZERO" -a "$COMMAND" != "NODISC" -a "$COMMAND" != "NOCHRG" ]; then echo "command from DB is not recognized, should be IDLE, CHARGE, DISCHARGE, NODISC, NOCHRG or ZERO, but value from DB is $COMMAND" COMMAND="IDLE" fi if [ "$P1_STATUS" != "online" ]; then # no info from P1 # set machine to idle echo "P1 is down, set SI to IDLE" COMMAND="IDLE" fi SI_OPERSTATUS=`modbus_read 40029` if [ "x$SI_OPERSTATUS" = "x" ]; then echo "unable to read Operating Status, device offline" exit fi echo "command" $COMMAND SMA_ENERGY_METER=`./sma-em01-production --oneshot` if [ "$?" = "1" ]; then echo error reading from SMA ENERGY METER, switch CHARGE and DISCHARGE to IDLE if [ "$COMMAND" = "DISCHARGE" -o "$COMMAND" = "CHARGE" ]; then COMMAND="IDLE" fi fi L1_CURRENT=`echo $SMA_ENERGY_METER | jq .l1_current` L1_VOLTAGE=`echo $SMA_ENERGY_METER | jq .l1_voltage` L1_ACTIVE_POWER_IN=`echo $SMA_ENERGY_METER | jq .l1_active_power_in | cut -f 1 -d .` L1_ACTIVE_POWER_OUT=`echo $SMA_ENERGY_METER | jq .l1_active_power_out | cut -f 1 -d .` L1_ACTIVE_POWER=$(($L1_ACTIVE_POWER_IN - $L1_ACTIVE_POWER_OUT)) echo L1 Grid active power to hub $L1_ACTIVE_POWER W echo L1 Grid voltage/current $L1_VOLTAGE V / $L1_CURRENT A L1_REACTIVE_POWER_IN=`echo $SMA_ENERGY_METER | jq .l1_reactive_power_in | cut -f 1 -d .` L1_REACTIVE_POWER_OUT=`echo $SMA_ENERGY_METER | jq .l1_reactive_power_out | cut -f 1 -d .` L1_REACTIVE_POWER=$(($L1_REACTIVE_POWER_IN - $L1_REACTIVE_POWER_OUT)) L1_APPARENT_POWER=`echo "scale=0; sqrt(($L1_ACTIVE_POWER)^2+($L1_REACTIVE_POWER)^2)" | bc` L1_MAX_APPARENT_POWER=`echo "scale=0; $L1_VOLTAGE*$MAX_AMP" | bc` L1_MAX_ACTIVE_POWER=`echo "scale=0; sqrt($L1_MAX_APPARENT_POWER^2 - ($L1_REACTIVE_POWER)^2)" | bc | cut -f 1 -d .` L1_SI60_ACTIVE_POWER=`modbus_read 31419` # combine data from SI60 and Grid L1_LOADS_AND_SOLAR_ACTIVE_POWER_FROM_HUB=$(($L1_ACTIVE_POWER-$L1_SI60_ACTIVE_POWER)) L1_LOADS_ACTIVE_POWER_FROM_HUB=$(($L1_ACTIVE_POWER-$L1_SI60_ACTIVE_POWER+$SOLAR_POWER)) L1_LOADS_AND_BATTERY_ACTIVE_POWER_FROM_HUB=$(($L1_ACTIVE_POWER+$SOLAR_POWER)) # compute max charge active power and max discharge active power L1_SI60_MAX_ACTIVE_POWER_FROM_HUB=$(($L1_MAX_ACTIVE_POWER-$L1_LOADS_AND_SOLAR_ACTIVE_POWER_FROM_HUB)) L1_SI60_MAX_ACTIVE_POWER_TO_HUB=$(($L1_MAX_ACTIVE_POWER+$L1_LOADS_AND_SOLAR_ACTIVE_POWER_FROM_HUB)) MAX_CHARGE=$L1_SI60_MAX_ACTIVE_POWER_FROM_HUB MAX_DISCHARGE=$L1_SI60_MAX_ACTIVE_POWER_TO_HUB echo L1 Grid max active power to/from hub $L1_MAX_ACTIVE_POWER W echo L1 loads and solar active power from hub $L1_LOADS_AND_SOLAR_ACTIVE_POWER_FROM_HUB W echo L1 loads active power from hub $L1_LOADS_ACTIVE_POWER_FROM_HUB echo L1 loads and battery active power from hub $L1_LOADS_AND_BATTERY_ACTIVE_POWER_FROM_HUB echo L1 SB40 active power to hub $SOLAR_POWER W echo L1 SI60 active power from hub $L1_SI60_ACTIVE_POWER W echo L1 SI60 max active power from hub $L1_SI60_MAX_ACTIVE_POWER_FROM_HUB W echo L1 SI60 max active power to hub $L1_SI60_MAX_ACTIVE_POWER_TO_HUB W SI_BATVOLT=`modbus_read 30851` SI_BATCURR=`modbus_read 30843` AHIN=`modbus_read 30567` AHOUT=`modbus_read 30569` TOTALVOLT=`echo "scale=2; $SI_BATVOLT/100" | bc` VOLTPERCELL=`echo "scale=2; $SI_BATVOLT/1600" | bc` TOTALCURR=`echo "scale=3; $SI_BATCURR/1000" | bc` echo SI battery charge in/out $AHIN/$AHOUT Ah echo SI battery voltage $TOTALVOLT V \($VOLTPERCELL V\) echo SI battery current $TOTALCURR A SI_POWER2=`modbus_read 30777` SI_CONDITION=`modbus_read 30201` SI_GRID_STATUS=`modbus_read 30883` case $SI_CONDITION in 35) echo SI Condition Fault ;; 303) echo SI Condition Off ;; 307) echo SI Condition OK ;; 455) echo SI Condition Warning ;; *) echo SI Condition $SI_CONDITION \(unknown code\) ;; esac case $SI_OPERSTATUS in 303) echo SI Operating Status OFF ;; 569) echo SI Operating Status Activated ;; 1295) echo SI Operating Status Standby ;; 1795) echo SI Operating Status Bolted ;; 16777213) echo SI Operating Status NaNStt ;; *) echo SI Operating Status $SI_OPERSTATUS \(unknown code\) ;; esac case $SI_GRID_STATUS in 35) echo SI Grid Status Fault \(Alm\) ;; 303) echo SI Grid Status Off ;; 1394) echo SI Grid Status Waiting for valid AC grid ;; 1787) echo SI Grid Status Initialization ;; 2183) echo SI Grid Status Mains oper. without feed back ;; 2184) echo SI Grid Status Energy saving in the network ;; 2185) echo SI Grid Status End energy saving in the network ;; 2186) echo SI Grid Status Start energy saving in the network ;; 1466) echo SI Grid Status About to enable Grid connection ;; 3068) echo SI Grid Status Mains operation with feedback ;; 16777213) echo SI Grid Status Information not available ;; *) echo SI Grid Status $SI_GRID_STATUS \(unknown code\) ;; esac #echo "SI power in" $SI_POWER_IN #echo "SI power out" $SI_POWER_OUT # negative means we are exporting power to the grid # positive means we are taking power from the grid #P1_POWER=$(($P1_POWER_IN - $P1_POWER_OUT)) # negative means we are exporting power to the grid # positive means we are taking power from the grid #SI_POWER=$(($SI_POWER_IN - $SI_POWER_OUT)) SI_POWER=$(($L1_ACTIVE_POWER_IN - $L1_ACTIVE_POWER_OUT)) # positive is from grid, negative is to grid #echo "P1 power" $P1_POWER # positive is from SI, negative is to SI # SI60 has a max power of 4600W MAX_POWER=4600 case $COMMAND in IDLE) SI_POWER_REQ=0 ;; CHARGE) if [ "$MAX_CHARGE" -le 0 ]; then echo "cant charge, no amps available at grid" COMMAND="IDLE" elif [ "-$MAX_POWER" -lt "-$MAX_CHARGE" ]; then echo "LIMITING CHARGING DUE TO MAX AMP AT GRID" SI_POWER_REQ=-$MAX_CHARGE else SI_POWER_REQ=-$MAX_POWER fi ;; DISCHARGE) if [ "$MAX_DISCHARGE" -le 0 ]; then echo "cant discharge, no amps available at grid" COMMAND="IDLE" elif [ "$MAX_POWER" -gt "$MAX_DISCHARGE" ]; then echo "LIMITING DISCHARGING DUE TO MAX AMP AT GRID" SI_POWER_REQ=-$MAX_CHARGE else SI_POWER_REQ=$MAX_POWER fi ;; ZERO) SI_POWER_REQ=$(($SI_POWER+$SI_POWER2)) ;; NOCHRG) SI_POWER_REQ=$(($SI_POWER+$SI_POWER2)) if [ "$SI_POWER_REQ" -le 0 ]; then # charge is requested, we don't do that, so switch to idle COMMAND="IDLE" fi #MAXCHRG=0 ;; NODISC) SI_POWER_REQ=$(($SI_POWER+$SI_POWER2)) if [ "$SI_POWER_REQ" -ge 0 ]; then # discharge is requested, we don't do that, so switch to idle COMMAND="IDLE" fi #MAXDISC=0 ;; *) echo "IMPOSSIBLE -> IDLE" COMMAND="IDLE" SI_POWER_REQ=0 esac echo Computed Active power setpoint $SI_POWER_REQ W BAT_PERC=`modbus_read 30845` echo "Battery SoC" $BAT_PERC % if [ "x$COMMAND" != "xIDLE" -a "$SI_POWER_REQ" -ge 0 -a "$BAT_PERC" -le 11 ]; then # inverter will misbehave when percentage is too low echo "battery low, do not discharge, we set the command to IDLE" COMMAND="IDLE" fi if [ "$SI_POWER_REQ" -ge 0 -a "$SI_BATVOLT" -le "4480" ]; then echo "battery voltage low. force idle" COMMAND="IDLE" fi echo "Max power used by Battery $MAX_POWER" if [ "$(($L1_LOADS_ACTIVE_POWER_FROM_HUB + $MAX_POWER))" -gt "$L1_MAX_ACTIVE_POWER" ]; then SOLAR_ALLOW=$((($L1_LOADS_ACTIVE_POWER_FROM_HUB - $L1_MAX_ACTIVE_POWER + $MAX_POWER)*10000/4000)) echo "Computed solar allow $SOLAR_ALLOW" else SOLAR_ALLOW=0 fi # limit solar by percentage, this somehow seems to work if [ "$PRICE" -lt 0 ]; then # limit to 0.00% echo "afknijpen met $SOLAR_ALLOW" mbpoll 192.168.1.126 -a 3 -B 3 -r 40023 -q -t 4 $SOLAR_ALLOW > /dev/null #mbpoll 192.168.1.126 -a 3 -B -0 -r 44039 -q -t 4:int 0 > /dev/null else # limit to 100.00% mbpoll 192.168.1.126 -a 3 -B 3 -r 40023 -q -t 4 10000 > /dev/null #mbpoll 192.168.1.126 -a 3 -B -0 -r 44039 -q -t 4:int 100000 > /dev/null fi if [ "x$COMMAND" = "xIDLE" ]; then #mbpoll 192.168.1.134 -a 3 -B -0 -r 40805 -q -t 4:int 303 > /dev/null #mbpoll 192.168.1.134 -a 3 -B -0 -r 40149 -q -t 4:int -- $SI_POWER_REQ > /dev/null #mbpoll 192.168.1.134 -a 3 -B -0 -r 40151 -q -t 4:int 802 > /dev/null mbpoll 192.168.1.134 -a 3 -B -0 -r 40805 -q -t 4:int 308 > /dev/null else mbpoll 192.168.1.134 -a 3 -B -0 -r 40805 -q -t 4:int 303 > /dev/null fi if [ "x$COMMAND" = "xZERO" -o "x$COMMAND" = "xNODISC" -o "x$COMMAND" = "xNOCHRG" ]; then #mbpoll 192.168.1.134 -a 3 -B -0 -r 40795 -q -t 4:int $MAXCHRG > /dev/null #mbpoll 192.168.1.134 -a 3 -B -0 -r 40799 -q -t 4:int $MAXDISC > /dev/null mbpoll 192.168.1.134 -a 3 -B -0 -r 40151 -q -t 4:int 803 > /dev/null mosquitto_pub -t si60h/command -m ZERO else #echo "setpoint comm. $SI_POWER_REQ" mbpoll 192.168.1.134 -a 3 -B -0 -r 40149 -q -t 4:int -- $SI_POWER_REQ > /dev/null mbpoll 192.168.1.134 -a 3 -B -0 -r 40151 -q -t 4:int 802 > /dev/null mosquitto_pub -t si60h/command -m $COMMAND fi echo "---------" mariadb -B --skip-column-names --user=$USERNAME --password=$PASSWORD stroom << EOQ INSERT INTO batstats ( batstat_timestamp, batstat_operstat, batstat_voltage, batstat_current, batstat_command, batstat_parameter, batstat_ahin, batstat_ahout ) VALUES ( $TIME, $SI_OPERSTATUS, $TOTALVOLT, $TOTALCURR, '$COMMAND', $SI_POWER_REQ, $AHIN, $AHOUT ) EOQ