def _login_and_fetch_site_info( power_wall: Powerwall, password: str ) -> tuple[SiteInfo, str]: """Login to the powerwall and fetch the base info.""" if password is not None: power_wall.login(password) return power_wall.get_site_info(), power_wall.get_gateway_din()
def main(): pp = pprint.PrettyPrinter(indent=2) creds = get_login_credentials() power_wall = Powerwall(POWERWALL_HOST) try: power_wall.detect_and_pin_version() except PowerwallUnreachableError as e: print(e) return print("Detected and pinned version: {}".format( power_wall.get_pinned_version())) _ = power_wall.login(creds["password"]) print("Current charge: {}".format(power_wall.get_charge())) print("Device Type: {}".format(power_wall.get_device_type())) print(f"Authenticated: {power_wall.get_api().is_authenticated()}") print(f"Sitemaster: {power_wall.get_sitemaster()}") print(f"Grid status: {power_wall.get_grid_status()}") print(f"Grid service activer: {power_wall.is_grid_services_active()}") site_info = power_wall.get_site_info() print(f"Site info: {pp.pformat(site_info.response)}") status = power_wall.get_status() print(f"Status: {pp.pformat(status.response)}") print(f"Device type: {power_wall.get_device_type()}") print(f"Serial numbers: {power_wall.get_serial_numbers()}") print(f"Version: {power_wall.get_version()}") # # XXX These methods need auth: print(f"Operation mode: {power_wall.get_operation_mode()}") # print(f"Backup reserved pct: {power_wall.get_backup_reserved_percentage()}") print(f"Solars: {power_wall.get_solars()}") print(f"VIN: {power_wall.get_vin()}") meters = power_wall.get_meters() # print(f"Meters: {pp.pformat(meters.response)}") for meter_type in MeterType: meter = meters.get_meter(meter_type) print(f"Meter: {meter_type}") print(f" Energy exported: {meter.energy_exported}") print(f" Energy imported: {meter.energy_imported}") print(f" Instant power: {meter.instant_power}") print(f" meter info: {pp.pformat(meter)}") # print(f" Instant reactive power: {meter.instant_reactive_power}") # print(f" Instant apparent power: {meter.instant_apparent_power}") # print(f" Instant average voltage: {meter.instant_average_voltage}") # print(f" Instant total current: {meter.instant_total_current}") # print(f" Is Active: {meter.is_active()}") # print(f" Is drawing from: {meter.is_drawing_from()}") # print(f" Is sending to: {meter.is_sending_to()}") return
def call_base_info(power_wall: Powerwall, host: str) -> PowerwallBaseInfo: """Return PowerwallBaseInfo for the device.""" # Make sure the serial numbers always have the same order gateway_din = None with contextlib.suppress(AssertionError, PowerwallError): gateway_din = power_wall.get_gateway_din().upper() return PowerwallBaseInfo( gateway_din=gateway_din, site_info=power_wall.get_site_info(), status=power_wall.get_status(), device_type=power_wall.get_device_type(), serial_numbers=sorted(power_wall.get_serial_numbers()), url=f"https://{host}", )
def main(): """ Get credentials from vault. Poke backup gateway. Push stats to influxdb """ vault = get_hvac_client() bg_creds = vault.secrets.kv.v1.read_secret(BG_GATEWAY_SECRETS_PATH) influxdb_creds = vault.secrets.kv.v1.read_secret(INFLUXDB_CREDS_PATH) powerwall = Powerwall(BG_GATEWAY_HOST) try: powerwall.detect_and_pin_version() except PowerwallUnreachableError as e: print(e) return _ = powerwall.login(bg_creds["email"], bg_creds["password"]) battery_pct_charge = powerwall.get_charge() site_info = powerwall.get_site_info() meters = power_wall.get_meters() meter_data = meters.response for (meter, data) in meters.items(): pass return
class TestPowerwall(unittest.TestCase): def setUp(self) -> None: self.powerwall = Powerwall(POWERWALL_IP) self.powerwall.login(POWERWALL_PASSWORD) def tearDown(self) -> None: self.powerwall.close() def test_get_charge(self) -> None: charge = self.powerwall.get_charge() self.assertIsInstance(charge, float) def test_get_meters(self) -> None: meters = self.powerwall.get_meters() self.assertIsInstance(meters, MetersAggregates) self.assertIsInstance(meters.site, Meter) self.assertIsInstance(meters.solar, Meter) self.assertIsInstance(meters.battery, Meter) self.assertIsInstance(meters.load, Meter) self.assertIsInstance(meters.get_meter(MeterType.SOLAR), Meter) for meter_type in MeterType: meter = meters.get_meter(meter_type) meter = meters.battery meter.energy_exported meter.energy_imported meter.instant_power meter.last_communication_time meter.frequency meter.average_voltage meter.get_energy_exported() meter.get_energy_imported() self.assertIsInstance(meter.get_power(), float) self.assertIsInstance(meter.is_active(), bool) self.assertIsInstance(meter.is_drawing_from(), bool) self.assertIsInstance(meter.is_sending_to(), bool) def test_sitemaster(self) -> None: sitemaster = self.powerwall.get_sitemaster() self.assertIsInstance(sitemaster, SiteMaster) sitemaster.status sitemaster.is_running sitemaster.is_connected_to_tesla sitemaster.is_power_supply_mode def test_site_info(self) -> None: site_info = self.powerwall.get_site_info() self.assertIsInstance(site_info, SiteInfo) site_info.nominal_system_energy site_info.site_name site_info.timezone def get_grid_status(self) -> None: grid_status = self.powerwall.get_grid_status() self.assertIsInstance(grid_status, GridStatus) def get_status(self) -> None: status = self.powerwall.get_status() self.assertIsInstance(status, PowerwallStatus) status.up_time_seconds status.start_time status.version
def _login_and_fetch_site_info(power_wall: Powerwall, password: str): """Login to the powerwall and fetch the base info.""" if password is not None: power_wall.login(password) power_wall.detect_and_pin_version() return power_wall.get_site_info()
class TestPowerWall(unittest.TestCase): def setUp(self): self.powerwall = Powerwall(ENDPOINT) def test_get_api(self): self.assertIsInstance(self.powerwall.get_api(), API) def test_pins_version_on_creation(self): pw = Powerwall(ENDPOINT, pin_version="1.49.0") self.assertEqual(pw.get_pinned_version(), version.LooseVersion("1.49.0")) pw = Powerwall(ENDPOINT, pin_version=version.LooseVersion("1.49.0")) self.assertEqual(pw.get_pinned_version(), version.LooseVersion("1.49.0")) @responses.activate def test_get_charge(self): add( Response(GET, url=f"{ENDPOINT}system_status/soe", json={"percentage": 53.123423})) self.assertEqual(self.powerwall.get_charge(), 53.123423) @responses.activate def test_get_sitemaster(self): add( Response(responses.GET, url=f"{ENDPOINT}sitemaster", json=SITEMASTER_RESPONSE)) sitemaster = self.powerwall.get_sitemaster() self.assertIsInstance(sitemaster, SiteMaster) self.assertEqual(sitemaster.status, "StatusUp") self.assertEqual(sitemaster.is_running, True) self.assertEqual(sitemaster.is_connected_to_tesla, True) self.assertEqual(sitemaster.is_power_supply_mode, False) @responses.activate def test_get_meters(self): add( Response(responses.GET, url=f"{ENDPOINT}meters/aggregates", json=METERS_AGGREGATES_RESPONSE)) meters = self.powerwall.get_meters() self.assertIsInstance(meters, MetersAggregates) self.assertIsInstance(meters.site, Meter) self.assertIsInstance(meters.solar, Meter) self.assertIsInstance(meters.battery, Meter) self.assertIsInstance(meters.load, Meter) self.assertIsInstance(meters.get_meter(MeterType.SOLAR), Meter) @responses.activate def test_meter(self): add( Response(responses.GET, url=f"{ENDPOINT}meters/aggregates", json=METERS_AGGREGATES_RESPONSE)) @responses.activate def test_is_sending(self): add( Response(responses.GET, url=f"{ENDPOINT}meters/aggregates", json=METERS_AGGREGATES_RESPONSE)) meters = self.powerwall.get_meters() self.assertEqual(meters.solar.is_sending_to(), False) self.assertEqual(meters.solar.is_active(), True) self.assertEqual(meters.solar.is_drawing_from(), True) self.assertEqual(meters.site.is_sending_to(), True) self.assertEqual(meters.load.is_sending_to(), True) self.assertEqual(meters.load.is_drawing_from(), False) self.assertEqual(meters.load.is_active(), True) @responses.activate def test_get_grid_status(self): add( Response(responses.GET, url=f"{ENDPOINT}system_status/grid_status", json=GRID_STATUS_RESPONSE)) grid_status = self.powerwall.get_grid_status() self.assertEqual(grid_status, GridStatus.CONNECTED) @responses.activate def test_is_grid_services_active(self): add( Response(responses.GET, url=f"{ENDPOINT}system_status/grid_status", json=GRID_STATUS_RESPONSE)) self.assertEqual(self.powerwall.is_grid_services_active(), False) @responses.activate def test_get_site_info(self): add( Response(responses.GET, url=f"{ENDPOINT}site_info", json=SITE_INFO_RESPONSE)) site_info = self.powerwall.get_site_info() self.assertEqual(site_info.nominal_system_energy, 27) self.assertEqual(site_info.site_name, "test") self.assertEqual(site_info.timezone, "Europe/Berlin") @responses.activate def test_get_status(self): add( Response(responses.GET, url=f"{ENDPOINT}status", json=STATUS_RESPONSE)) status = self.powerwall.get_status() self.assertEqual( status.up_time_seconds, datetime.timedelta(seconds=61891, microseconds=214751)) self.assertEqual( status.start_time, datetime.datetime(2020, 10, 28, 20, 14, 11, tzinfo=datetime.timezone( datetime.timedelta(seconds=28800)))) self.assertEqual(status.device_type, DeviceType.GW1) self.assertEqual(status.version, "1.50.1") @responses.activate def test_get_device_type(self): add( Response(responses.GET, url=f"{ENDPOINT}status", json=STATUS_RESPONSE)) device_type = self.powerwall.get_device_type() self.assertIsInstance(device_type, DeviceType) self.assertEqual(device_type, DeviceType.GW1) @responses.activate def test_get_serial_numbers(self): add( Response(responses.GET, url=f"{ENDPOINT}powerwalls", json=POWERWALLS_RESPONSE)) serial_numbers = self.powerwall.get_serial_numbers() self.assertEqual(serial_numbers, ["SerialNumber1", "SerialNumber2"]) @responses.activate def test_get_backup_reserved_percentage(self): add( Response(responses.GET, url=f"{ENDPOINT}operation", json=OPERATION_RESPONSE)) @responses.activate def test_get_operation_mode(self): add( Response(responses.GET, url=f"{ENDPOINT}operation", json=OPERATION_RESPONSE)) @responses.activate def test_get_version(self): add( Response(responses.GET, url=f"{ENDPOINT}status", json=STATUS_RESPONSE)) self.assertEqual(self.powerwall.get_version(), "1.50.1") @responses.activate def test_detect_and_pin_version(self): add( Response(responses.GET, url=f"{ENDPOINT}status", json=STATUS_RESPONSE)) vers = version.LooseVersion("1.50.1") pw = Powerwall(ENDPOINT) self.assertEqual(pw.detect_and_pin_version(), vers) self.assertEqual(pw._pin_version, vers) def test_helpers(self): resp = {"a": 1} with self.assertRaises(MissingAttributeError): assert_attribute(resp, "test") with self.assertRaises(MissingAttributeError): assert_attribute(resp, "test", "test") self.assertEqual(convert_to_kw(2500, -1), 2.5)
import os from tesla_powerwall import Powerwall def getenv(var): val = os.getenv(var) if val is None: raise ValueError(f"{var} must be set") return val ip = getenv("POWERWALL_IP") password = getenv("POWERWALL_PASSWORD") power_wall = Powerwall(ip) power_wall.login(password) # Identify the powerwall version power_wall.detect_and_pin_version() print("Detected and pinned version: {}".format( power_wall.get_pinned_version())) print("Current charge: {}".format(power_wall.get_charge())) print("Device Type: {}".format(power_wall.get_device_type())) print("Site Name: {}".format(power_wall.get_site_info().site_name))
class TestPowerWall(unittest.TestCase): def setUp(self): self.powerwall = Powerwall(ENDPOINT) def test_endpoint_setup(self): test_endpoint_1 = "1.1.1.1" pw = Powerwall(test_endpoint_1) self.assertEqual(pw._endpoint, f"https://{test_endpoint_1}/api/") test_endpoint_2 = "http://1.1.1.1" pw = Powerwall(test_endpoint_2) self.assertEqual(pw._endpoint, f"https://1.1.1.1/api/") test_endpoint_3 = "https://1.1.1.1/api/" pw = Powerwall(test_endpoint_3) self.assertEqual(pw._endpoint, test_endpoint_3) @responses.activate def test_get_charge(self): add( Response( GET, url=f"{ENDPOINT}system_status/soe", json={"percentage": 53.123423} ) ) self.assertEqual(self.powerwall.get_charge(), 53) self.assertEqual(self.powerwall.get_charge(rounded=False), 53.123423) @responses.activate def test_process_response(self): res = requests.Response() res.request = requests.Request(method="GET", url=f"{ENDPOINT}test").prepare() res.status_code = 401 with self.assertRaises(AccessDeniedError): self.powerwall._process_response(res) res.status_code = 502 with self.assertRaises(PowerwallUnreachableError): self.powerwall._process_response(res) res.status_code = 200 res._content = b'{"error": "test_error"}' with self.assertRaises(APIError): self.powerwall._process_response(res) res._content = b'{"response": "ok"}' self.assertEqual(self.powerwall._process_response(res), {"response": "ok"}) @responses.activate def test_get(self): add(Response(GET, url=f"{ENDPOINT}test_get", json={"test_get": True})) self.assertEqual(self.powerwall._get("test_get"), {"test_get": True}) @responses.activate def test_post(self): def post_callback(request): resp_body = {"test_post": True} headers = {} return (200, headers, json.dumps(resp_body)) responses.add_callback( responses.POST, url=f"{ENDPOINT}test_post", callback=post_callback, content_type="application/json", ) resp = self.powerwall._post("test_post", {"test": True}) self.assertIsInstance(resp, dict) self.assertEqual(resp, {"test_post": True}) @responses.activate def test_meters(self): add( Response( responses.GET, url=f"{ENDPOINT}meters/aggregates", json=METERS_RESPONSE ) ) meters = self.powerwall.get_meters() self.assertIsInstance(meters, MetersAggregateResponse) self.assertIsInstance(meters.site, MetersResponse) self.assertIsInstance(meters.solar, MetersResponse) self.assertIsInstance(meters.battery, MetersResponse) self.assertIsInstance(meters.load, MetersResponse) @responses.activate def test_is_sending(self): add( Response( responses.GET, url=f"{ENDPOINT}meters/aggregates", json=METERS_RESPONSE ) ) meters = self.powerwall.get_meters() self.assertEqual(meters.solar.is_sending_to(), False) self.assertEqual(meters.solar.is_active(), True) self.assertEqual(meters.solar.is_drawing_from(), True) self.assertEqual(meters.site.is_sending_to(), True) self.assertEqual(meters.load.is_sending_to(), True) self.assertEqual(meters.load.is_drawing_from(), False) self.assertEqual(meters.load.is_active(), True) @responses.activate def test_optional_json_attrs(self): add( Response( responses.GET, url=f"{ENDPOINT}site_info", json=SITE_INFO_RESPONSE_WITHOUT_OPTIONS, ) ) add( Response( responses.GET, url=f"{ENDPOINT}site_info", json=SITE_INFO_RESPONSE_WITH_OPTIONS, ) ) site_info = self.powerwall.get_site_info() self.assertEqual(site_info.has_optional_attrs_set(), False) self.assertEqual(site_info.has_key("utility"), False) self.assertEqual(site_info.grid_voltage_setting, 230) self.assertEqual(site_info.has_optional_attrs(), True) site_info = self.powerwall.get_site_info() self.assertEqual(site_info.has_optional_attrs_set(), True) self.assertEqual(site_info.has_key("utility"), True) self.assertEqual(site_info.retailer, "*")
class TestPowerwall(unittest.TestCase): def setUp(self) -> None: self.powerwall = Powerwall(POWERWALL_IP) self.powerwall.login(POWERWALL_PASSWORD) def tearDown(self) -> None: self.powerwall.close() def test_get_charge(self) -> None: charge = self.powerwall.get_charge() self.assertIsInstance(charge, float) def test_get_meters(self) -> None: meters = self.powerwall.get_meters() self.assertIsInstance(meters, MetersAggregates) self.assertIsInstance(meters.get_meter(MeterType.BATTERY), Meter) for meter_type in meters.meters: meter = meters.get_meter(meter_type) meter.energy_exported meter.energy_imported meter.instant_power meter.last_communication_time meter.frequency meter.average_voltage meter.get_energy_exported() meter.get_energy_imported() self.assertIsInstance(meter.get_power(), float) self.assertIsInstance(meter.is_active(), bool) self.assertIsInstance(meter.is_drawing_from(), bool) self.assertIsInstance(meter.is_sending_to(), bool) def test_sitemaster(self) -> None: sitemaster = self.powerwall.get_sitemaster() self.assertIsInstance(sitemaster, SiteMaster) sitemaster.status sitemaster.is_running sitemaster.is_connected_to_tesla sitemaster.is_power_supply_mode def test_site_info(self) -> None: site_info = self.powerwall.get_site_info() self.assertIsInstance(site_info, SiteInfo) site_info.nominal_system_energy site_info.site_name site_info.timezone def test_capacity(self) -> None: self.assertIsInstance(self.powerwall.get_capacity(), int) def test_energy(self) -> None: self.assertIsInstance(self.powerwall.get_energy(), int) def test_batteries(self) -> None: batteries = self.powerwall.get_batteries() self.assertGreater(len(batteries), 0) for battery in batteries: battery.wobble_detected battery.energy_discharged battery.energy_charged battery.energy_remaining battery.capacity battery.part_number battery.serial_number def test_grid_status(self) -> None: grid_status = self.powerwall.get_grid_status() self.assertIsInstance(grid_status, GridStatus) def test_status(self) -> None: status = self.powerwall.get_status() self.assertIsInstance(status, PowerwallStatus) status.up_time_seconds status.start_time status.version