Skip to content

Instantly share code, notes, and snippets.

@hyun007
Last active June 22, 2024 00:15
Show Gist options
  • Save hyun007/c689fbed10424b558f140c54851659e3 to your computer and use it in GitHub Desktop.
Save hyun007/c689fbed10424b558f140c54851659e3 to your computer and use it in GitHub Desktop.
span.io api documentation

Span.io API Documentation

The Span API does not at this time require any authentication. This will probably change in the future.

Description: Gets panel summary, firmware version, door state, serial number, network status Request: GET /api/v1/status Response:

{
  "software": {
    "firmwareVersion": "spanos2/r202216/04",
    "updateStatus": "idle",
    "env": "prod"
  },
  "system": {
    "manufacturer": "Span",
    "serial": "nt-2139-c1ac4",
    "model": "00200",
    "doorState": "OPEN",
    "uptime": 1475028
  },
  "network": {
    "eth0Link": false,
    "wlanLink": true,
    "wwanLink": false
  }
}

Description: Gets panel state, grid state, power draw for whole panel, and for each breaker Request: GET /api/v1/panel Response:

{
  "mainRelayState": "CLOSED",
  "instantGridPowerW": 8361.962890625,
  "feedthroughPowerW": -82.79021826386452,
  "gridSampleStartMs": 836674,
  "gridSampleEndMs": 836686,
  "dsmGridState": "DSM_GRID_UP",
  "dsmState": "DSM_ON_GRID",
  "currentRunConfig": "PANEL_ON_GRID",
  "branches": [
    {
      "id": 1,
      "relayState": "CLOSED",
      "instantPowerW": -3.015791177749634,
      "importedActiveEnergyWh": 1.4696391820907593,
      "exportedActiveEnergyWh": 12594.255859375
    },
    {
      "id": 2,
      "relayState": "CLOSED",
      "instantPowerW": -8.53760051727295,
      "importedActiveEnergyWh": 343.6731262207031,
      "exportedActiveEnergyWh": 19945.1328125
    },
    {
      "id": 3,
      "relayState": "CLOSED",
      "instantPowerW": -4.699003219604492,
      "importedActiveEnergyWh": 27.433591842651367,
      "exportedActiveEnergyWh": 6132.89697265625
    },
	...
  ]
}

Description: Get information on individual breakers, their positions, names, state, priority Request: GET /api/v1/circuits Response:

{
  "spaces": {
    "xxxxxxxxxxxxxxx": {
      "id": "xxxxxxxxxxxxxxx",
      "name": "Garage 220",
      "relayState": "CLOSED",
      "instantPowerW": -3625.2879638671875,
      "instantPowerUpdateTimeS": 1656531017,
      "importEnergyAccumWh": 4146.5565185546875,
      "exportEnergyAccumWh": 313066.625,
      "energyAccumUpdateTimeS": 1656530716,
      "tabs": [
        12,
        14
      ],
      "priority": "NOT_ESSENTIAL",
      "is_user_controllable": true,
      "is_sheddable": false,
      "is_never_backup": false
    },
    "xxxxxxxxxxxxxxx": {
      "id": "xxxxxxxxxxxxxxx",
      "name": "A/C condeser",
      "relayState": "CLOSED",
      "instantPowerW": -2428.6781005859375,
      "instantPowerUpdateTimeS": 1656531017,
      "importEnergyAccumWh": 11638.456787109375,
      "exportEnergyAccumWh": 752839.09375,
      "energyAccumUpdateTimeS": 1656530716,
      "tabs": [
        16,
        18
      ],
      "priority": "MUST_HAVE",
      "is_user_controllable": true,
      "is_sheddable": false,
      "is_never_backup": false
    },
    "xxxxxxxxxxxxxxx": {
      "id": "xxxxxxxxxxxxxxx",
      "name": "Tesla charger",
      "relayState": "CLOSED",
      "instantPowerW": -503.9554138183594,
      "instantPowerUpdateTimeS": 1656531017,
      "importEnergyAccumWh": 30.012138724327087,
      "exportEnergyAccumWh": 218781.4375,
      "energyAccumUpdateTimeS": 1656530716,
      "tabs": [
        26,
        28
      ],
      "priority": "NICE_TO_HAVE",
      "is_user_controllable": true,
      "is_sheddable": false,
      "is_never_backup": false
    },
    ...
  }
}

Description: Change breaker state, turn on/off a breaker Valid Values: OPEN, CLOSED Request: POST /api/v1/circuits/xxxxxxxxxxxxxxx

{
	"relay_state_in": {
		"relayState":"OPEN"
	}
}

Response:

{
	"id":"xxxxxxxxxxxxxxx",
	"name":"Garage outlets*",
	"relayState":"OPEN",
	"instantPowerW":0.0,
	"instantPowerUpdateTimeS":1656538555,
	"importEnergyAccumWh":722.7332153320312,
	"exportEnergyAccumWh":973.8363037109375,
	"energyAccumUpdateTimeS":1656538493,
	"tabs":[6],
	"priority":"NOT_ESSENTIAL",
	"is_user_controllable":true,
	"is_sheddable":false,
	"is_never_backup":false
}

Description: Change breaker priority Valid Values: MUST_HAVE, NICE_TO_HAVE, NOT_ESSENTIAL Request: POST /api/v1/circuits/xxxxxxxxxxxxxxx

{
	"priority_in": {
		"priority":"NICE_TO_HAVE"
	}
}

Response:

{
	"id":"xxxxxxxxxxxxxxx",
	"name":"Garage outlets*",
	"relayState":"OPEN",
	"instantPowerW":0.0,
	"instantPowerUpdateTimeS":1656539097,
	"importEnergyAccumWh":722.7332153320312,
	"exportEnergyAccumWh":973.8363037109375,
	"energyAccumUpdateTimeS":1656538493,
	"tabs":[6],
	"priority":"NICE_TO_HAVE",
	"is_user_controllable":true,
	"is_sheddable":false,
	"is_never_backup":false
}
@prs999
Copy link

prs999 commented Nov 24, 2023

Hi! I am using firmwareVersion=spanos2/r202342/04. I am unable register a user using the api:

curl -X "POST" "http://$tgt/api/v1/auth/register" -H "accept: application/json" -H "Content-Type: application/json" -H "Password: xxxxxxxx"
-d '{"name": "SPAN_API_User_2", "description": "SPAN_API_User_2 description" }'

I added the -H "Password: xxxxxxxx" without success or difference from the SPAN API.

The return response I am getting with/without the password is:
{"detail":"Must provide one-time-password, dashboard password or door-bypass"}

Are you able to use the latest firmwareVersion?

V/R,
Paul

@smatsmats
Copy link

I think you still need to do the 3 (I think) button pushes to do the registration calls.

I'm probably still using a token snagged from a web browser login.

@prs999
Copy link

prs999 commented Dec 1, 2023

Could you please provide more details --- 3 button pushes?!? What are you referring to? How did you login from the browser?

@patniemeyer
Copy link

patniemeyer commented Dec 17, 2023

Could you please provide more details --- 3 button pushes?!? What are you referring to? How did you login from the browser?

Find the local IP address using a network scanner or perhaps the DHCP table on your router. The web UI login page will appear on that IP. It prompts for a password or instructs that you can push the door button (the switch at the top that closes when you close the door) three times to open up access for a set time. You can then log into the web UI without the password. At that point you can see the calls that it is making by e.g. using your web browsers developer tools... Look at the request header of one of the /circuits requests and just copy the bearer token from it. Paste it in replacing the ones in the examples above, e.g.

curl -X GET "http://[MY IP]/api/v1/circuits" -H "Authorization: bearer [MY TOKEN]“ 

@patniemeyer
Copy link

For fun I have made a little CLI tool that shows circuits data in a sorted table, kind of like the "top" command. python script. Thanks to @hyun007 for his work on the API.

@BrianLawes
Copy link

BrianLawes commented Jan 5, 2024

Thanks hyun007 and patneimeyer. This script and all the info is great.

I modified patneimeyer's script to call /api/vi/panel, save it to a json file, and get the below info as part of the content. Any idea what the relayState means? All of mine are showing CLOSED for all 32 id fields.

..
"branches": [
{
"id": 1,
"relayState": "CLOSED",
"instantPowerW": 0.9801977276802063,
"importedActiveEnergyWh": 84.47095489501953,
"exportedActiveEnergyWh": 32.3878288269043
},
{
"id": 2,
"relayState": "CLOSED",
"instantPowerW": -0.25444918870925903,
"importedActiveEnergyWh": 0.31798499822616577,
"exportedActiveEnergyWh": 5361.7060546875
},
...

If anyone also knows the definition of the other fields that would also be helpful.

Cheers!!

@cayossarian
Copy link

cayossarian commented Feb 19, 2024

@BrianLawes The relay state is the physical relay behind the circuit breaker. If you turn a circuit off in the app the relay will be open (the breaker will still be "set" or closed but the circuit will not receive power. They do warn you that if you are doing electrical work to manually open the circuit breaker though and not rely on the relay).

@residualimages
Copy link

Are there any known updates to security or calling on the POSTs for Priority? I can toggle relayState successfully with various POSTs, but the Priority eludes me.

image

image

@patrick-sullivan
Copy link

@residualimages Whatever changed, it's broken in the panel's baked-in Circuits view as well (http://<span_ip_here>/#/circuits). I just tried changing priorities using the drop-downs there there and even that gets a 500 back and fails to actually apply the change.

This is on firmware spanos2/r202405/02.

@cayossarian
Copy link

anyone find endpoints with info about solar? i've got inverters hooked up to my panel but that specific breaker is omitted from the circuits endpoint.

Solar is not currently identified in circuit list but there is a list of all the circuits power, etc. in the panel data. data["branches"][] so you can add one or two circuits together to get the information where you solar is connected.

There is a Home Assistant custom HACS repository that provides solar sensors in this manner. You'll need to add a custom HACS repository as this feature is not currently in the default HACS SPAN integration.https://github.com/cayossarian/span

@ericsmith66
Copy link

FYI For the change breaker state example, I think it should read relayStateIn instead of relay_state_in.

@PaulSAtGitHub
Copy link

Thanks for the inputs earlier!

I have a rough iOS app. I started this project because we have multiple SpanPanels and several are daisy chained and the SpanApp only allows you to work with a single panel at a time. I do plan on having an export button to jumpstart HomeAssistant configuration.

image

App allows for multiple Plans. You scan the local network and find the SpanPanel(s). Each panel is then registered.

image

Both Wifi and Ethernet address is captured --- working on identifying which is which and prioritizing Ethernet for later requests

image

Circuit Panels are drawn as they appear in the panel

image

Monitoring allows filtering out of circuits based upon usage while cumulating the results so you can identify the big hitters across all panels.

Paul

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment