PowerWall Data Integration


Thx for yr suggestions in this thread …

To recap - I’m trying to adapt the published so I can grab more data from another Tesla API – eg: battery instant power.

I have no Python expertise but mindful that an infinite number of chimps given an infinite amount of time could type The Bible, like a chimp I set to work. But after days spent on this, I’m now heartily sick of bananas. For example, it took me 2 days to discover that in Python to comment out a line it was necessary to use #space – who’d have thought that?

I finally settled on what I thought was a methodical approach. Below is a version of the original with all the alternatives I can think of as comment lines – I could swap lines in/out easily using nano.

import time, json, Cargo, requests
from emonhub_interfacer import EmonHubInterfacer

"""class EmonHubTeslaPowerWallInterfacer

Fetch Tesla Power Wall state of charge


class EmonHubTeslaPowerWallInterfacer(EmonHubInterfacer):

    def __init__(self, name):


        # Interfacer specific settings
        self._template_settings = {'name': 'powerwall',
                                   'url': False,
                                   'readinterval': 10.0}

        # FIXME is there a good reason to reduce this from the default of 1000? If so, document it here.
        # set an absolute upper limit for number of items to process per post
        self._item_limit = 250

        # Fetch first reading at one interval lengths time
        self._last_time = 0

    def read(self):
        # Request Power Wall data at user specified interval
        if time.time() - self._last_time >= self._settings['readinterval']:
            self._last_time = time.time()

            # If URL is set, fetch the SOC
            if self._settings['url']:
                # HTTP Request
                    reply = requests.get(self._settings['url'], timeout=int(self._settings['readinterval']), verify=False)
					# aggregates = requests.get(self._settings['url'], timeout=10, verify=False).json()  # per @bwduncan
                    # aggregates = requests.get(self._settings['url'], timeout=10, verify=False)  # per @bwduncan but no .json()
					# reply = requests.get(self._settings['url'], timeout=10, verify=False).json()  # per @bwduncan & reply
                    # reply = requests.get(self._settings['url'], timeout=10, verify=False)  # per @bwduncan but no .json() & reply
					reply.raise_for_status()  # Raise an exception if status code isn't 200
                except requests.exceptions.RequestException as ex:
                    self._log.warning("%s couldn't send to server: %s",, ex)

                jsonstr = reply.text.rstrip()
                self._log.debug("%s Request response: %s",, jsonstr)

                # Decode JSON
                    data = json.loads(jsonstr)
                except Exception:  # FIXME Too general exception
                    self._log.warning("%s Invalid JSON",

                # Create cargo object
                c = Cargo.new_cargo()
                c.nodeid = self._settings['name']
                c.names = ["soc"]
                # c.realdata = [data['percentage']]
				c.realdata = [data['battery']['instant_power']]
				# c = Cargo.new_cargo(names=['battery_instant_power'], realdata=[aggregates['battery']['instant_power'])   # per @bwduncan
				# c = Cargo.new_cargo(names=['battery_instant_power'], realdata=[data['battery']['instant_power'])   # per @bwduncan but data
				# c = Cargo.new_cargo(names=['battery_instant_power'], realdata=[aggregates['battery']['instant_power']])  # added ]
                return c

        # return empty if not time

    def set(self, **kwargs):
        for key, setting in self._template_settings.items():
            # Decide which setting value to use
            if key in kwargs.keys():
                setting = kwargs[key]
                setting = self._template_settings[key]
            if key in self._settings and self._settings[key] == setting:
            elif key == 'readinterval':
      "Setting %s %s: %s",, key, setting)
                self._settings[key] = float(setting)
            elif key == 'name':
      "Setting %s %s: %s",, key, setting)
                self._settings[key] = setting
            elif key == 'url':
      "Setting %s %s: %s",, key, setting)
                self._settings[key] = setting
                self._log.warning("'%s' is not valid for %s: %s", setting,, key)

        # include kwargs from parent

But whatever alternative I’ve tried, I always got a popup error message and emonhub stopped (but could be restarted with … sudo systemctl start emonhub.service)

EmonCMS Error


Message: SyntaxError: unexpected token: identifier

Route: Lib/jquery-1.11.3.min.js

Line: 1

Column: 4

The emonhub log is not informative.

Then, quite by chance, I ran as is but with a url containing /api/meters/aggregates

The log revealed the wealth of data that is available …

2020-07-31 23:12:48,043 DEBUG    PowerWall  PowerWall Request response: {"site":{"last_communication_time":"2020-07-31T23:12:47.889536541+01:00","instant_power":4.8070068359375,"instant_reactive_power":169.26604461669922,"instant_apparent_power":169.33428824341266,"frequency":49.95012283325195,"energy_exported":1101936.5047250446,"energy_imported":876557.3925028223,"instant_average_voltage":124.1665776570638,"instant_total_current":0,"i_a_current":0,"i_b_current":0,"i_c_current":0,"timeout":1500000000},"battery":{"last_communication_time":"2020-07-31T23:12:47.890245881+01:00","instant_power":2130,"instant_reactive_power":-20,"instant_apparent_power":2130.0938946440833,"frequency":49.969,"energy_exported":319410,"energy_imported":393570,"instant_average_voltage":248.33333333333334,"instant_total_current":-50.3,"i_a_current":0,"i_b_current":0,"i_c_current":0,"timeout":1500000000},"load":{"last_communication_time":"2020-07-31T23:12:47.889536541+01:00","instant_power":2147.7866236629907,"instant_reactive_power":151.9973041128399,"instant_apparent_power":2153.158275938683,"frequency":49.95012283325195,"energy_exported":0,"energy_imported":-299539.11222222226,"instant_average_voltage":124.1665776570638,"instant_total_current":17.297622791819002,"i_a_current":0,"i_b_current":0,"i_c_current":0,"timeout":1500000000},"solar":{"last_communication_time":"2020-07-31T23:12:47.890574865+01:00","instant_power":0,"instant_reactive_power":0,"instant_apparent_power":0,"frequency":0,"energy_exported":0,"energy_imported":0,"instant_average_voltage":0,"instant_total_current":0,"i_a_current":0,"i_b_current":0,"i_c_current":0,"timeout":1500000000}}
2020-07-31 23:12:48,044 WARNING  PowerWall  PowerWall Percentage key not found

And the warning – PowerWall Percentage key not found – suggests the code operated OK to that point. And emonhub continued to operate.

I’d more than welcome any further suggestions.

And I’m happy to be a testbed of any ideas suggested by those not having a PowerWall.


From a browser, what URL do you use, and what do you get back?

Basic steps are

  1. Create return object (cargo)
  2. Send URL
  3. Load cargo with data returned from URL.
  4. return cargo

If you want to use 2 URLs, do steps 2 & 3 again so

  1. Create return object (cargo)
  2. Send URL 1
  3. Load cargo with data returned from URL 1.
  4. Send URL 2
  5. Load cargo with data returned from URL 2.
  6. return cargo