Example #1
0
 def __read_variant_2_element(self, element: str) -> str:
     response = req.get_http_session().get(
         'http://' + self.__device_address + ':7979/rest/devices/battery/' +
         element,
         timeout=5)
     response.encoding = 'utf-8'
     return response.text.strip(" \n\r")
Example #2
0
    def update(self, bat: bool) -> Tuple[CounterState, MeterLocation]:
        variant = self.component_config["configuration"]["variant"]
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")

        session = req.get_http_session()

        if variant == 0 or variant == 1:
            counter_state, meter_location = self.__update_variant_0_1(session)
        elif variant == 2:
            counter_state, meter_location = self.__update_variant_2(session)
        else:
            raise FaultState.error("Unbekannte Variante: " + str(variant))

        if meter_location == MeterLocation.load:
            response = session.get(
                'http://' + self.device_config["ip_address"] +
                '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
                params=(('Scope', 'System'), ),
                timeout=5)
            counter_state.power = float(
                response.json()["Body"]["Data"]["Site"]["P_Grid"])
            topic_str = "openWB/set/system/device/{}/component/{}/".format(
                self.__device_id, self.component_config["id"])
            # Beim Energiebezug ist nicht klar, welcher Anteil aus dem Netz bezogen wurde, und was aus
            # dem Wechselrichter kam.
            # Beim Energieexport ist nicht klar, wie hoch der Eigenverbrauch während der Produktion war.
            counter_state.imported, counter_state.exported = self.__sim_count.sim_count(
                counter_state.power,
                topic=topic_str,
                data=self.simulation,
                prefix="bezug")

        return counter_state, meter_location
Example #3
0
def powerwall_update(address: str, email: str, password: str,
                     update_function: UpdateFunction):
    log.debug("Beginning update")
    cookies = None
    try:
        cookies = json.loads(COOKIE_FILE.read_text())
    except FileNotFoundError:
        log.debug("Cookie-File <%s> does not exist. It will be created.",
                  COOKIE_FILE)
    except JSONDecodeError as e:
        log.warning("Could not parse Cookie-File <%s>. It will be re-created.",
                    COOKIE_FILE,
                    exc_info=e)

    session = get_http_session()
    if cookies is None:
        _authenticate_and_update(session, address, email, password,
                                 update_function)
        return
    try:
        update_function(PowerwallHttpClient(address, session, cookies))
        return
    except HTTPError as e:
        if e.response.status_code != 401 and e.response.status_code != 403:
            raise e
        log.warning(
            "Login to powerwall with existing cookie failed. Will retry with new cookie..."
        )
    _authenticate_and_update(session, address, email, password,
                             update_function)
    log.debug("Update completed successfully")
Example #4
0
 def __get_wr2(self) -> Tuple[float, float]:
     ip_address2 = self.component_config["configuration"]["ip_address2"]
     counter2 = 0
     if ip_address2 != "none":
         try:
             params = (('Scope', 'System'), )
             response = req.get_http_session().get(
                 'http://' + ip_address2 +
                 '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
                 params=params,
                 timeout=3)
             response.raise_for_status()
             try:
                 power2 = float(
                     response.json()["Body"]["Data"]["Site"]["P_PV"])
             except TypeError:
                 # Ohne PV Produktion liefert der WR 'null', ersetze durch Zahl 0
                 power2 = 0
             if not self.component_config["configuration"]["gen24"]:
                 counter2 = float(
                     response.json()["Body"]["Data"]["Site"]["E_Total"])
         except (requests.ConnectTimeout, requests.ConnectionError):
             # Nachtmodus: WR ist ausgeschaltet
             power2 = 0
     else:
         power2 = 0
     return power2, counter2
Example #5
0
    def update(self) -> float:
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")

        # Rückgabewert ist die aktuelle Wirkleistung in [W].
        params = (('Scope', 'System'), )
        response = req.get_http_session().get(
            'http://' + self.device_config["ip_address"] +
            '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
            params=params,
            timeout=3)
        try:
            power = float(response.json()["Body"]["Data"]["Site"]["P_PV"])
        except TypeError:
            # Ohne PV Produktion liefert der WR 'null', ersetze durch Zahl 0
            power = 0

        power2 = self.__get_wr2()
        power += power2
        power1 = power
        power *= -1
        topic = "openWB/set/system/device/" + str(
            self.__device_id) + "/component/" + str(
                self.component_config["id"]) + "/"
        _, counter = self.__sim_count.sim_count(power,
                                                topic=topic,
                                                data=self.__simulation,
                                                prefix="pv")

        inverter_state = InverterState(power=power, counter=counter)
        self.__store.set(inverter_state)
        # Rückgabe der Leistung des ersten WR ohne Vorzeichenumkehr
        return power1
Example #6
0
def request_value(url: str) -> Optional[float]:
    if "none" == url:
        return None
    else:
        response = req.get_http_session().get(url, timeout=5)
        response.encoding = 'utf-8'
        log.debug("Antwort auf " + str(url) + " " + str(response.text))
        return float(response.text.replace("\n", ""))
Example #7
0
 def get_values(self) -> Tuple[float, float]:
     '''BYD Speicher bieten zwei HTML-Seiten, auf denen Informationen abgegriffen werden können:
     /asp/Home.asp und /asp/RunData.asp. Aktuell (2022-03) ist die Leistungsangabe (Power) auf der
     RunData.asp auf ganze kW gerundet und somit für openWB nicht brauchbar.
     '''
     resp = req.get_http_session().get(
         'http://' + self.__device_config.configuration.ip_address + '/asp/Home.asp',
         auth=(self.__device_config.configuration.username,  self.__device_config.configuration.password))
     return BydParser.parse(resp.text)
Example #8
0
    def get_values(self) -> Tuple[float, float]:
        params = (('dxsEntries', ['67109120', '251658753']),)
        resp = req.get_http_session().get('http://'+self.ip_address+'/api/dxs.json', params=params, timeout=3).json()
        power = float(resp["dxsEntries"][0]["value"])
        if power > 5:
            power = power*-1

        exported = float(resp["dxsEntries"][1]["value"]) * 1000
        return power, exported
Example #9
0
    def read_inverter_state(self) -> InverterState:
        log.debug("Komponente "+self.component_config["name"]+" auslesen.")
        data = {'RPC': '{"version": "1.0","proc": "GetPlantOverview","id": "1","format": "JSON"}'}
        response = req.get_http_session().post(
            'http://' + self.__device_address + '/rpc', data=data, timeout=3).json()

        return InverterState(
            counter=float(response["result"]["overview"][2]["value"]) * 1000,
            power=-int(response["result"]["overview"][0]["value"])
        )
Example #10
0
    def update(self, bat: bool) -> float:
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")
        gen24 = self.component_config["configuration"]["gen24"]

        # Rückgabewert ist die aktuelle Wirkleistung in [W].
        params = (('Scope', 'System'), )
        response = req.get_http_session().get(
            'http://' + self.device_config["ip_address"] +
            '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
            params=params,
            timeout=3)
        try:
            power = float(response.json()["Body"]["Data"]["Site"]["P_PV"])
        except TypeError:
            # Ohne PV Produktion liefert der WR 'null', ersetze durch Zahl 0
            power = 0

        power2, counter2 = self.__get_wr2()
        power += power2
        power1 = power
        power *= -1
        topic = "openWB/set/system/device/" + str(
            self.__device_id) + "/component/" + str(
                self.component_config["id"]) + "/"
        if gen24:
            _, counter = self.__sim_count.sim_count(power,
                                                    topic=topic,
                                                    data=self.__simulation,
                                                    prefix="pv")
        else:
            counter = float(response.json()["Body"]["Data"]["Site"]["E_Total"])
            daily_yield = float(
                response.json()["Body"]["Data"]["Site"]["E_Day"])
            counter, counter_start, counter_offset = self.__calculate_offset(
                counter, daily_yield)
            counter = counter + counter2
            if counter > 0:
                counter = self.__add_and_save_offset(daily_yield, counter,
                                                     counter_start,
                                                     counter_offset)

        if bat is True:
            _, counter = self.__sim_count.sim_count(power,
                                                    topic=topic,
                                                    data=self.__simulation,
                                                    prefix="pv")

        inverter_state = InverterState(power=power,
                                       counter=counter,
                                       currents=[0, 0, 0])
        self.__store.set(inverter_state)
        # Rückgabe der Leistung des ersten WR ohne Vorzeichenumkehr
        return power1
Example #11
0
 def update(self) -> None:
     log.MainLogger().debug("Start device reading " + str(self._components))
     if self._components:
         with MultiComponentUpdateContext(self._components):
             response = req.get_http_session().get(self.device_config["configuration"]["ip_address"], timeout=5)
             for component in self._components:
                 self._components[component].update(response.json())
     else:
         log.MainLogger().warning(
             self.device_config["name"] +
             ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden."
         )
Example #12
0
 def get_values(self) -> Tuple[float, List[float]]:
     params = (('dxsEntries', ['83887106', '83887362', '83887618']), )
     resp = req.get_http_session().get('http://' + self.ip_address +
                                       '/api/dxs.json',
                                       params=params,
                                       timeout=3).json()["dxsEntries"]
     powers = [
         float(resp[0]["value"]),
         float(resp[1]["value"]),
         float(resp[2]["value"])
     ]
     home_consumption = sum(powers)
     return home_consumption, powers
Example #13
0
    def read(self) -> InverterState:
        data = {
            'RPC':
            '{"version": "1.0","proc": "GetPlantOverview","id": "1","format": "JSON"}'
        }
        response = req.get_http_session().post('http://' +
                                               self.__device_address + '/rpc',
                                               data=data,
                                               timeout=3).json()

        return InverterState(
            exported=float(response["result"]["overview"][2]["value"]) * 1000,
            power=-int(response["result"]["overview"][0]["value"]))
Example #14
0
 def update(self) -> None:
     log.debug("Start device reading " + str(self.components))
     if self.components:
         with MultiComponentUpdateContext(self.components):
             resp_json = req.get_http_session().get(
                 'http://' + self.device_config.configuration.ip_address + '/api.php?get=currentstate',
                 timeout=5).json()
             for component in self.components:
                 self.components[component].update(resp_json)
     else:
         log.warning(
             self.device_config.name +
             ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden."
         )
Example #15
0
def update(bydhvip: str, bydhvuser: str, bydhvpass: str):
    '''BYD Speicher bieten zwei HTML-Seiten, auf denen Informationen abgegriffen werden können:
    /asp/Home.asp und /asp/RunData.asp. Aktuell (2022-03) ist die Leistungsangabe (Power) auf der
    RunData.asp auf ganze kW gerundet und somit für openWB nicht brauchbar.
    '''
    log.debug("Beginning update")
    bat_info = ComponentInfo(None, "BYD", "bat")
    with SingleComponentUpdateContext(bat_info):
        # response = req.get_http_session().get('http://' + bydhvip + '/asp/RunData.asp', auth=(bydhvuser, bydhvpass))
        response = req.get_http_session().get('http://' + bydhvip +
                                              '/asp/Home.asp',
                                              auth=(bydhvuser, bydhvpass))
        get_bat_value_store(1).set(BydParser.parse(response.text))
    log.debug("Update completed successfully")
Example #16
0
def fetch_soc(akey: str, token: str) -> Union[int, float]:
    response = req.get_http_session().get("https://app.evnotify.de/soc",
                                          params={
                                              "akey": akey,
                                              "token": token
                                          })
    try:
        soc_display = response.json()[_SOC_PROPERTY]
        if not isinstance(soc_display, (int, float)):
            raise Exception("Number expected, got <{}>, type={}".format(
                soc_display, type(soc_display)))
        return soc_display
    except Exception as e:
        raise Exception(
            "Expected object with numeric property <{}>. Got: <{}>".format(
                _SOC_PROPERTY, response.text)) from e
Example #17
0
    def update(self) -> None:
        params = (
            ('CAN', '1'),
            ('HASH', '00200403'),
            ('TYPE', '1'),
        )
        response = req.get_http_session().get(
            "http://" + self.ip_address + "/data/ajax.txt",
            params=params,
            auth=HTTPDigestAuth("customer", self.password))
        values = response.text.split(';')

        inverter_state = InverterState(power=float(values[1].split(' ')[0]) *
                                       -1,
                                       exported=float(values[16]) * 1000)
        self.__store.set(inverter_state)
Example #18
0
    def update(self) -> None:
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")
        params = (
            ('CAN', '1'),
            ('HASH', '00200403'),
            ('TYPE', '1'),
        )
        response = req.get_http_session().get(
            "http://" + self.ip_address + "/data/ajax.txt",
            params=params,
            auth=HTTPDigestAuth("customer", self.password))
        values = response.text.split(';')

        inverter_state = InverterState(power=float(values[1].split(' ')[0]) *
                                       -1,
                                       counter=float(values[16]) * 1000)
        self.__store.set(inverter_state)
Example #19
0
    def update(self) -> None:

        session = req.get_http_session()
        variant = self.component_config.configuration.variant
        if variant == 0 or variant == 1:
            counter_state = self.__update_variant_0_1(session)
        elif variant == 2:
            counter_state = self.__update_variant_2(session)
        else:
            raise FaultState.error("Unbekannte Variante: " + str(variant))

        topic_str = "openWB/set/system/device/{}/component/{}/".format(
            self.__device_id, self.component_config.id)
        counter_state.imported, counter_state.exported = self.__sim_count.sim_count(
            counter_state.power,
            topic=topic_str,
            data=self.simulation,
            prefix="bezug")
        self.__store.set(counter_state)
Example #20
0
    def update(self) -> None:
        session = req.get_http_session()
        response = session.get('http://' + self.device_config.ip_address +
                               '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
                               timeout=5)
        # Wenn WR aus bzw. im Standby (keine Antwort), ersetze leeren Wert durch eine 0.
        power = float(response.json()["Body"]["Data"]["Site"]["P_Grid"]) or 0

        topic_str = "openWB/set/system/device/{}/component/{}/".format(
            self.__device_id, self.component_config.id)
        imported, exported = self.__sim_count.sim_count(power,
                                                        topic=topic_str,
                                                        data=self.simulation,
                                                        prefix="bezug")

        counter_state = CounterState(imported=imported,
                                     exported=exported,
                                     power=power)
        self.__store.set(counter_state)
Example #21
0
 def read_power(self) -> float:
     # Rückgabewert ist die aktuelle Wirkleistung in [W].
     try:
         params = (('Scope', 'System'), )
         response = req.get_http_session().get(
             'http://' + self.device_config.ip_address +
             '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
             params=params,
             timeout=3)
         try:
             power = float(
                 response.json()["Body"]["Data"]["Site"]["P_PV"]) * -1
         except TypeError:
             # Ohne PV Produktion liefert der WR 'null', ersetze durch Zahl 0
             power = 0
     except (requests.ConnectTimeout, requests.ConnectionError):
         # Nachtmodus: WR ist ausgeschaltet
         power = 0
     return power
Example #22
0
    def update(self) -> None:
        log.debug("Start device reading " + str(self.components))
        if self.components:
            with MultiComponentUpdateContext(self.components):
                session = req.get_http_session()
                response = self._request_data(session)
                # missing "auth" in response indicates success
                if (response.get('auth') == "auth_key failed"
                        or response.get('auth') == "auth timeout"
                        or response.get('auth') == "not done"):
                    self._update_session_key(session)
                    response = self._request_data(session)

                for component in self.components:
                    self.components[component].update(response)
        else:
            log.warning(
                self.device_config.name +
                ": Es konnten keine Werte gelesen werden, da noch keine Komponenten konfiguriert wurden."
            )
Example #23
0
File: bat.py Project: okaegi/openWB
    def update(self) -> BatState:
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")
        meter_id = str(self.device_config["meter_id"])

        resp_json = req.get_http_session().get(
            'http://' + self.device_config["ip_address"] +
            '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
            params=(('Scope', 'System'), ),
            timeout=5).json()
        try:
            power = int(resp_json["Body"]["Data"]["Site"]["P_Akku"]) * -1
        except TypeError:
            # Wenn WR aus bzw. im Standby (keine Antwort), ersetze leeren Wert durch eine 0.
            power = 0

        try:
            resp_json_id = dict(resp_json["Body"]["Data"])
            if "Inverters" in resp_json_id:
                soc = float(resp_json_id["Inverters"]["1"]["SOC"])
            else:
                soc = float(
                    resp_json_id.get(meter_id)["Controller"]
                    ["StateOfCharge_Relative"])
        except TypeError:
            # Wenn WR aus bzw. im Standby (keine Antwort), ersetze leeren Wert durch eine 0.
            soc = 0

        topic_str = "openWB/set/system/device/" + str(
            self.__device_id) + "/component/" + str(
                self.component_config["id"]) + "/"
        imported, exported = self.__sim_count.sim_count(power,
                                                        topic=topic_str,
                                                        data=self.__simulation,
                                                        prefix="speicher")
        bat_state = BatState(power=power,
                             soc=soc,
                             imported=imported,
                             exported=exported)
        return bat_state
Example #24
0
    def update(self) -> Tuple[CounterState, MeterLocation]:
        variant = self.component_config["configuration"]["variant"]
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")

        session = req.get_http_session()

        if variant == 0 or variant == 1:
            counter_state, meter_location = self.__update_variant_0_1(session)
        elif variant == 2:
            counter_state, meter_location = self.__update_variant_2(session)
        else:
            raise FaultState.error("Unbekannte Variante: " + str(variant))

        topic_str = "openWB/set/system/device/{}/component/{}/".format(
            self.__device_id, self.component_config["id"])
        counter_state.imported, counter_state.exported = self.__sim_count.sim_count(
            counter_state.power,
            topic=topic_str,
            data=self.simulation,
            prefix="bezug")

        return counter_state, meter_location
Example #25
0
    def update(self) -> None:
        log.debug("Beginning update")
        cookies = None
        address = self.device_config.configuration.ip_address
        email = self.device_config.configuration.email
        password = self.device_config.configuration.password
        with MultiComponentUpdateContext(self.components):
            try:
                cookies = json.loads(COOKIE_FILE.read_text())
            except FileNotFoundError:
                log.debug(
                    "Cookie-File <%s> does not exist. It will be created.",
                    COOKIE_FILE)
            except JSONDecodeError:
                log.warning("Could not parse Cookie-File " + str(COOKIE_FILE) +
                            ". It will be re-created.",
                            exc_info=True)

            session = get_http_session()
            if cookies is None:
                self.__authenticate_and_update(session, address, email,
                                               password,
                                               self.__update_components)
                return
            try:
                self.__update_components(
                    PowerwallHttpClient(address, session, cookies))
                return
            except HTTPError as e:
                if e.response.status_code != 401 and e.response.status_code != 403:
                    raise e
                log.warning(
                    "Login to powerwall with existing cookie failed. Will retry with new cookie..."
                )
            self.__authenticate_and_update(session, address, email, password,
                                           self.__update_components)
            log.debug("Update completed successfully")
Example #26
0
    def update(self, bat: bool) -> CounterState:
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")

        session = req.get_http_session()
        response = session.get('http://' + self.device_config["ip_address"] +
                               '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
                               timeout=5)
        # Wenn WR aus bzw. im Standby (keine Antwort), ersetze leeren Wert durch eine 0.
        power = float(response.json()["Body"]["Data"]["Site"]["P_Grid"]) or 0

        # Summe der vom Netz bezogene Energie total in Wh
        # nur für Smartmeter  im Einspeisepunkt!
        # bei Smartmeter im Verbrauchszweig  entspricht das dem Gesamtverbrauch
        response = session.get('http://' + self.device_config["ip_address"] +
                               '/solar_api/v1/GetMeterRealtimeData.cgi',
                               params=(('Scope', 'System'), ),
                               timeout=5)
        meter_id = str(self.device_config["meter_id"])
        response_json_id = dict(response.json()["Body"]["Data"]).get(meter_id)
        if "EnergyReal_WAC_Minus_Absolute" in response_json_id and \
           "EnergyReal_WAC_Plus_Absolute" in response_json_id:
            imported = float(response_json_id["EnergyReal_WAC_Minus_Absolute"])
            exported = float(response_json_id["EnergyReal_WAC_Plus_Absolute"])
        else:
            topic_str = "openWB/set/system/device/{}/component/{}/".format(
                self.__device_id, self.component_config["id"])
            imported, exported = self.__sim_count.sim_count(
                power, topic=topic_str, data=self.simulation, prefix="bezug")

        counter_state = CounterState(imported=imported,
                                     exported=exported,
                                     power=power)
        log.MainLogger().debug("Fronius SM Leistung[W]: " +
                               str(counter_state.power))
        return counter_state
Example #27
0
    def update(self) -> CounterState:
        log.MainLogger().debug("Komponente " + self.component_config["name"] +
                               " auslesen.")

        session = req.get_http_session()
        response = session.get('http://' + self.device_config["ip_address"] +
                               '/solar_api/v1/GetPowerFlowRealtimeData.fcgi',
                               timeout=5)
        # Wenn WR aus bzw. im Standby (keine Antwort), ersetze leeren Wert durch eine 0.
        power = float(response.json()["Body"]["Data"]["Site"]["P_Grid"]) or 0

        topic_str = "openWB/set/system/device/{}/component/{}/".format(
            self.__device_id, self.component_config["id"])
        imported, exported = self.__sim_count.sim_count(power,
                                                        topic=topic_str,
                                                        data=self.simulation,
                                                        prefix="bezug")

        counter_state = CounterState(imported=imported,
                                     exported=exported,
                                     power=power)
        log.MainLogger().debug("Fronius S0 Leistung[W]: " +
                               str(counter_state.power))
        return counter_state
Example #28
0
 def __read_variant_1(self):
     return req.get_http_session().get("http://" + self.__device_address +
                                       "/api/v1/status",
                                       timeout=5).json()
Example #29
0
 def __read_variant_0(self):
     return req.get_http_session().get('http://' + self.__device_address +
                                       ':7979/rest/devices/battery',
                                       timeout=5).json()
Example #30
0
 def __init__(self, device_config: dict) -> None:
     settings = device_config["configuration"]
     self.__session = get_http_session()
     self.__session.auth = (settings["user"], settings["password"])
     self._components = []  # type: List[DiscovergyComponent]