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
Exemple #3
0
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}",
    )
Exemple #4
0
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
Exemple #6
0
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()
Exemple #7
0
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)
Exemple #8
0
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))
Exemple #9
0
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