I've had solar power for a couple of years now. The package included a Fronius inverter and a stack of panels; and while I made sure the the Fronius came with the WiFi adapter and at least some monitoring, it's ... well lacklustre.

Recently I've been building myself Grafana dashboards (because all the cool kids are doing it). And since the inverter has its own little webserver onboard, I dug into it - and what do you know, it's relatively "current" tech wise, using JSON to update the data on the client.

Well I can parse that! Here's how it all fits together.

InfluxDB for Data Storage

I happen to use InfluxDB for my data storage. Why? Well because ... I just do. It was the one that everyone seemed to be using.

I won't run through the whole setup guide for InfluxDB - suffice it to say mine lives on a Linux VM and its datastores are on a separate (growable) virtual disk. No special data grooming, I'll deal with that if I ever have to.

The "schema" for the data is very simple:

Measurement
Column NameData "Type"Description
timenanosecondsTimestamp for Data Point
InstantWattsActual generation at time of retrieval
LifetimeWatt-HoursTotal lifetime power generation
TodayWatt-HoursTotal generation "today"
YearWatt-HoursTotal generation this calendar year
StatusIntegerInverter status - I don't use this yet
MessageStringReason for status code - I don't use this yet

BASH Script for Data Gathering

All the data is gathered using a script started at boot. You'll need to have the wget and jq tools installed (or adjust the script appropriately). Don't forget to set the variables at the top to suit your environment:

#!/bin/bash

# This script pulls JSON data from a Fronius solar inverter

# The time we are going to sleep between readings
sleeptime=10

# Dependencies:
#  jq (JSON command line parser)

endpoint=IPADDRESS_OR_HOSTNAME_OF_INVERTER 
ephost=FRIENDLY_NAME_FOR_INVERTER
database=INFLUXDB_NAME
series=MEASUREMENT_NAME

get_json_data () {
    #Get JSON data
    tempdatafile=/tmp/JSONdata-$endpoint

    wget http://$endpoint/solar_api/v1/GetPowerFlowRealtimeData.fcgi -qO $tempdatafile

    Status=`cat $tempdatafile | jq '.Head.Status.Code'`
    Reason=`cat $tempdatafile | jq '.Head.Status.Reason'`
    Message=`cat $tempdatafile | jq '.Head.Status.UserMessage'`
    PVOutput=`cat $tempdatafile | jq '.Body.Data.Site.P_PV'`
    PVDaily=`cat $tempdatafile | jq '.Body.Data.Site.E_Day'`
    PVAnnual=`cat $tempdatafile | jq '.Body.Data.Site.E_Year'`
    PVTotal=`cat $tempdatafile | jq '.Body.Data.Site.E_Total'`

    if [ -z $Status ]; then Status="0"; fi
    if [[ -z $Reason || $Reason == "null" || $Reason = "\"\"" ]]; then Reason=; fi
    if [[ -z $Message || $Message == "null" || $Message = "\"\"" ]]; then Message=; fi
    if [[ -z $PVOutput || $PVOutput == "null" ]]; then PVOutput="0"; fi
    if [ -z $PVDaily ]; then PVDaily="0"; fi
    if [ -z $PVAnnual ]; then PVAnnual="0"; fi
    if [ -z $PVTotal ]; then PVTotal="0"; fi

    rm $tempdatafile
}

print_data () {
    echo "System Status: $Status"
    echo "Reason: $Reason"
    echo "Message: $Message"
    echo "Instantaneous Output: $PVOutput W"
    echo "Output Today: $PVDaily Wh"
    echo "Output This Year: $PVAnnual Wh"
    echo "Output Lifetime: $PVTotal Wh"
}

write_data () {
    #Write the data to the database
    data=$''$series',host='$ephost' Status='$Status
    data=$data$'\n'$series',host='$ephost' Reason="'$Reason'"'
    data=$data$'\n'$series',host='$ephost' Message="'$Message'"'
    data=$data$'\n'$series',host='$ephost' Instant='$PVOutput
    data=$data$'\n'$series',host='$ephost' Today='$PVDaily
    data=$data$'\n'$series',host='$ephost' Year='$PVAnnual
    data=$data$'\n'$series',host='$ephost' Lifetime='$PVTotal

    echo "Write data:\n"$data
    curl -i -XPOST 'http://localhost:8086/write?db='$database --data-binary "$data"
}

#Prepare to start the loop and warn the user

echo "Press [CTRL+C] to stop..."
while :
do
    # Retrieve the data
    get_json_data

    #Output console data for future reference
    print_data

    # Store the data in Influx
    write_data

    if [[ $1 == "once" ]];
      then
        exit 0
    fi
    #Sleep between readings
    sleep "$sleeptime"
done

You can test by running it with the "once" parameter before you set it up in your init/systemctl database:

grafana:~$ sudo /var/lib/influxscripts/http-solar.sh once
Press [CTRL+C] to stop...
System Status: 0
Reason:
Message:
Instantaneous Output: 3277 W
Output Today: 21338 Wh
Output This Year: 2555065 Wh
Output Lifetime: 31261123 Wh
Write data:\nSolar,host=solar Status=0 Solar,host=solar Reason="" Solar,host=solar Message="" Solar,host=solar Instant=3277 Solar,host=solar Today=21338 Solar,host=solar Year=2555065 Solar,host=solar Lifetime=31261123
HTTP/1.1 204 No Content
Content-Type: application/json
Request-Id: 4173314c-02e5-11e7-a694-000000000000
X-Influxdb-Version: 1.2.0
Date: Tue, 07 Mar 2017 03:22:12 GMT

Grafana for Display

Here's a snapshot of the dashboard for my system.

Logically there are only 2 data rows (the numbers and the graphs) but that's not too critical - it's just the way I did it to simplify setting row heights. The first row is the quick data view with some colour coding of the "today" output to highlight how effective it is:

 Next, the graph of "today's" production. Obviously if you tweak the display dates, this will change, but the default setup is "today". Today is a mixed bag of sun and rain.

Then some historical data. First the last month (well, 30 days is close):

Then the last year. Shows the seasonal change, and the density highlights good and bad periods:

Then the last 5 years. This is where I'm hoping I can spot some longer term trends (such as "overall production is down because the panels are degrading with age"). Unfortunately a lot of the older data includes only the daily totals as I had to export it from the manufacturer portal.

The JSON for the dashboard itself is 21kB. If you want to use it for your own Grafana instance you're more than welcome.

Download the dashboard definition file.