# Local Monitoring using FCGI Web Services
SunStrong Management is pleased to announce an API for local PVS monitoring.  The API is available on the PVS Ethernet and Wi-Fi interfaces and can be used to access some of the legacy dl_cgi APIs as well as the new varserver FCGI APIs.

These APIs will support local communication between the PVS and the SunStrong Connect application, as well as custom monitoring solutions developed by system owners and the open source development community.

The interface supports Basic Authentication (username/password).  Users must authenticate before accessing the dl_cgi and FCGI APIs.  Some limited Varserver data points and dl_cgi endpoints are available without authentication.

Varserver is a highly efficient in-memory key-value data store used for system configuration management, telemetry reporting, and inter-process communications.  Data is stored/retrieved as unstructured primitive data points which represent a single telemetry value or configuration/control point.  Some data is represented as JSON object structures stored in string variables.

The Varserver web services only expose two APIs:

- auth - user login/logout

- vars - Varserver interface for setting and getting variables

## Our commitment to open source
The SunStrong Management team have made available the following open source components to support the community:

- A Python wrapper around the VarServer FCGI web services (PyPVS)

- A Home Assistant plugin which can be installed in Home Assistant via the Home Assistant Community Store (HACS).

### Availability
The FCGI Web services and authenticated dl_cgi endpoints are available in PVS6 firmware build 61840 and later.  Support for PVS5 devices is coming soon.  PVS2 devices are not, and will never be supported.

### Disclaimer
Use of this interface is at your own risk.  SunStrong Management is releasing these components as-is, and assume no liability for use/mis-use of these components. 

## Theory of Operation
For most users, the PyPVS library and HA plugin will be sufficient to get started, but for those interested in the more technical details of the API, read on….

### Authentication
Before accessing data, users must authenticate against the PVS using a username and password.  The username is: ssm_owner
The password is: the last 5 characters of the PVS serial number

Upon successful login, the requester receives an access token which is then delivered (via a cookie) to the PVS in subsequent data queries.  

### Data queries:
Data points can be queried by name; by partial name match; by tags; and by cache id.  Any query can be associated with a user specified cache id, and then subsequently retrieved using that cache id.  Users can arbitrarily group data points as needed and retrieve those groupings by cache id.  Note that match queries search the entire varserver name space and are less efficient than cached queries.  It is strongly recommended, particularly when making frequent match or tag queries, to cache the query, and then make subsequent queries using the cache id.   While the varserver FCGI interface is very efficient, we do not recommend making queries faster than once every few seconds, in case you overload the PVS CPU.  This is particularly important on SunVault systems where the CPU already has a lot to do.

### Data Output Formats
Two data output formats are currently supported:

- a JSON array containing one object per data point with name and value, and possibly other attributes in future

- a JSON object containing key/value pairs, where the key is the datapoint name, and the value is its current value.

### Available data points
This list is subject to change, and we will most likely not be updating it regularly.  To check the data points available on your system, run a match query, but beware this will generate a lot of data.

Check the attached file [Varserver Variables](varserver-variables-public.csv) for the list of currenlty accessible variables.

### Examples
All the examples are shown below using curl to demonstrate the API features.
in all the examples below:

- **pwd** = <last 5 digits of PVS serial number>
- **ip** = <IP address of PVS>
- **cookies.txt** is a file containing cookies (used to store auth tokens)

The `jq` utility is used to format the response into a more readable format

Please check https://github.com/tjmonk/fcgi_vars for more details about the API.

#### Authentication - login
```
$ auth=`echo -n "ssm_owner:$pwd" | base64`
$ curl -k \
       -b cookies.txt \
       -c cookies.txt \
       -H "Authorization: basic $auth" \
       https://$ip/auth?login 
{"session": "3z02Z55QKi4VZevR6EW4psExaTNZaiaGGeUBqKlXnHIJBPoPV6uzztgcAXGd3rFf" }
$ cat cookies.txt
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_localhost     FALSE   /       TRUE    0       session NCA7CIW7zoXxsFfWAH64OrrNS6OrN2zU0hTAcgtUvCMqOsug98TldqceGBxI2ZxK
```

#### Authentication - logout
```
$ curl -k \
       -b cookies.txt \
       -c cookies.txt \
       -H "Authorization: basic $auth" \
       https://$ip/auth?logout 
```

#### Query a list of variables by name
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       https://$ip/vars?name=/sys/info/sw_rev,/sys/info/lmac | jq
{
  "values": [
    {
      "name": "/sys/info/sw_rev",
      "value": "2025.06.24.61840"
    },
    {
      "name": "/sys/info/lmac",
      "value": "00:22:F2:13:85:54"
    }
  ],
  "count": 2
}
```

#### Set a variable by name
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       https://$ip/vars?set=/sys/telemetryws/enable=1 | jq
{
  "values": [
    {
      "name": "/sys/telemetryws/enable",
      "value": "1"
    }
  ],
  "count": 1
}
```

#### Query all variables which match a substring
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       https://$ip/vars?match=rev | jq
{
  "values": [
    {
      "name": "/sys/info/hwrev",
      "value": "6.03"
    },
    {
      "name": "/sys/info/fwrev",
      "value": " Major 2, Revision 0x00000001, Build 3"
    },
    {
      "name": "/sys/info/sw_rev",
      "value": "2025.06.24.61840"
    }
  ],
  "count": 3
}
```

#### Query all variables which match a substring and output as an object
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       "https://$ip/vars?match=rev&fmt=obj" | jq
{
  "/sys/info/hwrev": "6.03",
  "/sys/info/fwrev": " Major 2, Revision 0x00000001, Build 3",
  "/sys/info/sw_rev": "2025.06.24.61840"
}
```

#### Query all livedata power values using a match expression, create a cache, and output as an object
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       "https://$ip/vars?match=livedata&fmt=obj&cache=ldata" | jq
{
  "/sys/livedata/time": "1751083263",
  "/sys/livedata/pv_p": "0.015622",
  "/sys/livedata/pv_en": "40747.871094",
  "/sys/livedata/net_p": "0.674694",
  "/sys/livedata/net_en": "6121.310059",
  "/sys/livedata/site_load_p": "1.876316",
  "/sys/livedata/site_load_en": "46378.703125",
  "/sys/livedata/ess_en": "-490.477997",
  "/sys/livedata/ess_p": "1.186000",
  "/sys/livedata/soc": "0.860000",
  "/sys/livedata/backupTimeRemaining": "570",
  "/sys/livedata/midstate": "2"
}
```

#### Query a cached data set and output as an object
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       "https://$ip/vars?fmt=obj&cache=ldata" | jq
{
  "/sys/livedata/time": "1751083345",
  "/sys/livedata/pv_p": "0.023758",
  "/sys/livedata/pv_en": "40747.871094",
  "/sys/livedata/net_p": "0.653675",
  "/sys/livedata/net_en": "6121.330078",
  "/sys/livedata/site_load_p": "2.539433",
  "/sys/livedata/site_load_en": "46378.734375",
  "/sys/livedata/ess_en": "-490.463989",
  "/sys/livedata/ess_p": "1.862000",
  "/sys/livedata/soc": "0.860000",
  "/sys/livedata/backupTimeRemaining": "555",
  "/sys/livedata/midstate": "2"
}
```

#### Query all meter data values using a match expression, create a cache, and output as an object
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       "https://$ip/vars?match=meter/data&fmt=obj&cache=mdata" | jq
{
  "/sys/devices/11/meter/data": {
    "ctSclFctr": 50,
    "freqHz": 60.0150032,
    "msmtEps": "2025-06-28T04:10:00Z",
    "netLtea3phsumKwh": 40747.87,
    "p3phsumKw": 0.0158712063,
    "prodMdlNm": "PVS6M0400p",
    "q3phsumKvar": 1.25327051,
    "s3phsumKva": 1.26208436,
    "sn": "PVS6M23084354p",
    "totPfRto": 0.00977255497,
    "v12V": 248.283142,
    "vldFldMsk": "67174655"
  },
  "/sys/devices/12/meter/data": {
    "ctSclFctr": 300,
    "freqHz": 60.0150032,
    "i1A": 13.9226713,
    "i2A": 12.32792,
    "msmtEps": "2025-06-28T04:10:00Z",
    "negLtea3phsumKwh": 13600.36,
    "netLtea3phsumKwh": 6121.360000000001,
    "p1Kw": 0.316900551,
    "p2Kw": 0.16260837,
    "p3phsumKw": 0.479508936,
    "posLtea3phsumKwh": 19721.78,
    "prodMdlNm": "PVS6M0400c",
    "q3phsumKvar": -3.15799665,
    "s3phsumKva": 3.25863361,
    "sn": "PVS6M23084354c",
    "totPfRto": 0.196262509,
    "v12V": 248.283142,
    "v1nV": 124.040031,
    "v2nV": 124.243462,
    "vldFldMsk": "70239999"
  }
}
```

#### Query all inverter data, create a cache, and output as an object
```
$ curl -s \
       -k \
       -b cookies.txt \
       -c cookies.txt \
       "https://$ip/vars?match=inverter/data&fmt=obj&cache=mdata" | jq
{
  "/sys/devices/21/inverter/data": {
    "freqHz": 60.01,
    "iMppt1A": 0.03,
    "ltea3phsumKwh": 686.5164000000001,
    "msmtEps": "2025-06-28T03:35:00Z",
    "pMppt1Kw": 0.00068,
    "prodMdlNm": "AC_Module_Type_H",
    "sn": "E00122307107854",
    "tHtsnkDegc": 24,
    "vMppt1V": 17.93,
    "vldFld2Msk": "1",
    "vldFldMsk": "8125",
    "vln3phavgV": 249.54
  },
  ...
  "/sys/devices/61/inverter/data": {
    "freqHz": 60.01,
    "iMppt1A": 0.04,
    "ltea3phsumKwh": 731.5522,
    "msmtEps": "2025-06-28T03:35:00Z",
    "pMppt1Kw": 0.00058,
    "prodMdlNm": "AC_Module_Type_H",
    "sn": "E00122308008125",
    "tHtsnkDegc": 24,
    "vMppt1V": 13.09,
    "vldFld2Msk": "1",
    "vldFldMsk": "8125",
    "vln3phavgV": 249.84
  }
}
```
