The EmonHubTeslaPowerWallInterfacer works well publishing the Battery % Charge to emoncms.
However there is another Tesla API (unofficially available) with a wealth of additional battery data – most importantly – instant power and total energy imported & exported.
Per below, I’ve managed to adapt my EmonHubTeslaPowerWallInterfacer.py file to capture this additional data and publish it to emoncms …
import time, json, Cargo, requests
from emonhub_interfacer import EmonHubInterfacer
"""class EmonHubTeslaPowerWallInterfacer
Fetch Tesla Power Wall power and energy
url needs a trailing /
"""
class EmonHubTeslaPowerWallInterfacer(EmonHubInterfacer):
def __init__(self, name):
super().__init__(name)
self._settings.update(self._defaults)
# 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 POWER and ENERGY
if self._settings['url']:
# HTTP Request
try:
reply = requests.get(self._settings['url'] + 'api/meters/aggregates', timeout=int(self._settings['readinterval']), verify=False)
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", self.name, ex)
jsonstr = reply.text.rstrip()
self._log.debug("%s Request response: %s", self.name, jsonstr)
# Decode JSON
try:
data = json.loads(jsonstr)
except Exception: # FIXME Too general exception
self._log.warning("%s Invalid JSON", self.name)
return
# Create cargo object
c = Cargo.new_cargo()
c.nodeid = self._settings['name']
c.names = ["power and energy"]
c.realdata = [data['battery']['instant_power'], data['battery']['energy_exported'], data['battery']['energy_imported']] # All in watts and +ve power=discharging -ve power=charging
return c
# return empty if not time
return
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]
else:
setting = self._template_settings[key]
if key in self._settings and self._settings[key] == setting:
continue
elif key == 'readinterval':
self._log.info("Setting %s %s: %s", self.name, key, setting)
self._settings[key] = float(setting)
continue
elif key == 'name':
self._log.info("Setting %s %s: %s", self.name, key, setting)
self._settings[key] = setting
continue
elif key == 'url':
self._log.info("Setting %s %s: %s", self.name, key, setting)
self._settings[key] = setting
continue
else:
self._log.warning("'%s' is not valid for %s: %s", setting, self.name, key)
# include kwargs from parent
super().set(**kwargs)
This approach means I can only run one or the other version – not both at the same time.
I am confused about whether a new Child Class should be created or whether this should be just another Object in the same Child Class.
Also what changes need to be made to the Interfacer stanza in emonhub.conf?
@TrystanLea – I would really appreciate yr guidance - thx
PS - There is a small annoyance. Per this screenshot of the Inputs page, the 2nd and 3rd data items have meaningless titles.