diff --git a/.bumpversion-dev.toml b/.bumpversion-dev.toml index bf69e3f..480297e 100644 --- a/.bumpversion-dev.toml +++ b/.bumpversion-dev.toml @@ -1,5 +1,5 @@ [tool.bumpversion] -current_version = "1.9.11" +current_version = "1.10.2" parse = "(?P\\d+)\\.(?P\\d+)\\.(?P\\d+)" serialize = ["{major}.{minor}.{patch}"] search = "{current_version}" @@ -11,11 +11,13 @@ tag = false sign_tags = false tag_name = "{new_version}" tag_message = "Bump version: {current_version} → {new_version}" -allow_dirty = false +allow_dirty = true commit = false message = "Bump version: {current_version} → {new_version}" commit_args = "" [[tool.bumpversion.files]] filename="./GridboxConnectorAddon-dev/config.yaml" [[tool.bumpversion.files]] -filename="./GridboxConnectorAddon-dev/cloudSettings.json" \ No newline at end of file +filename="./GridboxConnectorAddon-dev/cloudSettings.json" +[[tool.bumpversion.files]] +filename="./GridboxConnectorAddon-dev/rootfs/share/cloudSettings.json" \ No newline at end of file diff --git a/.bumpversion.toml b/.bumpversion.toml index 9cb984d..58df3d6 100644 --- a/.bumpversion.toml +++ b/.bumpversion.toml @@ -18,8 +18,8 @@ commit_args = "" [[tool.bumpversion.files]] filename="./GridboxConnectorAddon/config.yaml" [[tool.bumpversion.files]] -filename="./GridboxConnectorAddon/cloudSettings.json" +filename="./GridboxConnectorAddon/rootfs/share/cloudSettings.json" [[tool.bumpversion.files]] filename="./GridboxConnectorAddon-dev/config.yaml" [[tool.bumpversion.files]] -filename="./GridboxConnectorAddon-dev/cloudSettings.json" \ No newline at end of file +filename="./GridboxConnectorAddon-dev/rootfs/share/cloudSettings.json" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1dd97f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +.pytest_cache +.history \ No newline at end of file diff --git a/GridboxConnectorAddon-dev/CHANGELOG.md b/GridboxConnectorAddon-dev/CHANGELOG.md index 1deff21..cb23d4d 100644 --- a/GridboxConnectorAddon-dev/CHANGELOG.md +++ b/GridboxConnectorAddon-dev/CHANGELOG.md @@ -1,5 +1,25 @@ +## 1.10.2 + +## Added + +- Added new sensor `directConsumptionHousehold` and `directConsumptionHeatPump` to show the direct consumption of the household +- Added new sensor `totalConsumption` to show the total consumption of the household +- Added Classes for the sensor to start with unit tests + +## Fixed + +- Fixed the issue with the battery sum sensor +- Fixed the issue with the battery sum appliance id +- Fixed the issue with each battery show now correct values + +## 1.9.12 + +## Fixed + +- Fixed Battery Sum set_state + ## 1.9.11 ## Fixed diff --git a/GridboxConnectorAddon-dev/GridboxConnector/Battery.py b/GridboxConnectorAddon-dev/GridboxConnector/Battery.py deleted file mode 100644 index 2a936bf..0000000 --- a/GridboxConnectorAddon-dev/GridboxConnector/Battery.py +++ /dev/null @@ -1,34 +0,0 @@ -from ha_mqtt_discoverable.sensors import Sensor, SensorInfo -from ha_mqtt_discoverable import Settings - -class Battery: - def __init__(self, mqtt_settings, device_info, name, id): - self.id = id - self.name = name - self.device_info = device_info - self.mqtt_settings = mqtt_settings - - self.battery_sensor_info = SensorInfo(name=f"Battery {name} Level", device_class="battery", unique_id=f"gridbox_battery_{name}", device=device_info, unit_of_measurement="%") - self.battery_settings = Settings(mqtt=mqtt_settings, entity=self.battery_sensor_info) - self.battery_level = Sensor(self.battery_settings) - - self.battery_sensor_capacity = SensorInfo(name=f"Battery {name} Capacity", device_class="energy", unique_id=f"gridbox_battery_level_{name}", device=device_info, unit_of_measurement="Wh") - self.battery_settings_capacity = Settings(mqtt=mqtt_settings, entity=self.battery_sensor_capacity) - self.battery_capacity = Sensor(self.battery_settings_capacity) - - self.battery_sensor_power = SensorInfo(name=f"Battery {name} Power", device_class="battery", unique_id=f"gridbox_battery_power_{name}", device=device_info, unit_of_measurement="W") - self.battery_settings_power = Settings(mqtt=mqtt_settings, entity=self.battery_sensor_power) - self.battery_power = Sensor(self.battery_settings_power) - - self.battery_sensor_remaining_charge = SensorInfo(name=f"Battery {name} Remaining Charge", device_class="energy", unique_id=f"gridbox_remaining_charge_{name}", device=device_info, unit_of_measurement="Wh") - self.battery_settings_remaining_charge = Settings(mqtt=mqtt_settings, entity=self.battery_sensor_remaining_charge) - self.battery_remaining_charge = Sensor(self.battery_settings_remaining_charge) - - def get_name(self): - return self.name - - def set_states(self, level, capacity, power, remaining_charge): - self.battery_level.set_state(level) - self.battery_capacity.set_state(capacity) - self.battery_power.set_state(power) - self.battery_remaining_charge.set_state(remaining_charge) \ No newline at end of file diff --git a/GridboxConnectorAddon-dev/GridboxConnector/__main__.py b/GridboxConnectorAddon-dev/GridboxConnector/__main__.py index 401d21b..7ba945e 100644 --- a/GridboxConnectorAddon-dev/GridboxConnector/__main__.py +++ b/GridboxConnectorAddon-dev/GridboxConnector/__main__.py @@ -1,10 +1,9 @@ import os import json import time -from ha_mqtt_discoverable import Settings, DeviceInfo -from ha_mqtt_discoverable.sensors import Sensor, SensorInfo from gridbox_connector import GridboxConnector -from Battery import Battery +from ha_mqtt_discoverable import Settings +from ha_viessmann_gridbox_connector import HAViessmannGridboxConnector if __name__ == '__main__': f = open('/build/cloudSettings.json') @@ -13,142 +12,30 @@ data = json.load(f) f.close() print("Start Viessmann Connector") - #print(f"====Version {data["version"]}====") + # print(f"====Version {data["version"]}====") options_file = open('/data/options.json') options_json = json.load(options_file) WAIT = int(options_json["wait_time"]) USER = os.getenv('USERNAME') PASSWORD = os.environ.get('PASSWORD') - mqtt_user = os.getenv('MqttUser') - mqtt_pw = os.getenv('MqttPw') - mqtt_server = os.getenv('MqttServer') - mqtt_port = os.getenv('MqttPort') + mqtt_user = os.getenv('MqttUser', "") + mqtt_pw = os.getenv('MqttPw', "") + mqtt_server = os.getenv('MqttServer', "") + mqtt_port = os.getenv('MqttPort', "") data["login"]["username"] = USER data["login"]["password"] = PASSWORD print(data["login"]) one_time_print = True - - battery_dict = {} - - mqtt_settings = Settings.MQTT(host=mqtt_server, username=mqtt_user, password=mqtt_pw) - - device_info = DeviceInfo(name="Viessmann Gridbox", identifiers="viessmann_gridbox", manufacturer="Viessmann", model="Vitocharge 2.0") - - production_sensor_info = SensorInfo(name="Production", device_class="power", unique_id="gridbox_production", device=device_info, unit_of_measurement="W") - production_settings = Settings(mqtt=mqtt_settings, entity=production_sensor_info) - - grid_sensor_info = SensorInfo(name="Grid", device_class="power", unique_id="gridbox_grid", device=device_info, unit_of_measurement="W") - grid_settings = Settings(mqtt=mqtt_settings, entity=grid_sensor_info) - - photovoltaic_sensor_info = SensorInfo(name="Photovoltaic", device_class="power", unique_id="gridbox_photovoltaic", device=device_info, unit_of_measurement="W") - photovoltaic_settings = Settings(mqtt=mqtt_settings, entity=photovoltaic_sensor_info) - - # consumption - consumption_household_sensor_info = SensorInfo(name="Consumption", device_class="power", unique_id="gridbox_consumption_household", device=device_info, unit_of_measurement="W") - consumption_household_settings = Settings(mqtt=mqtt_settings, entity=consumption_household_sensor_info) - - total_consumption_household_sensor_info = SensorInfo(name="Total Consumption", device_class="power", unique_id="total_consumption_household", device=device_info, unit_of_measurement="W") - total_consumption_household_settings = Settings(mqtt=mqtt_settings, entity=total_consumption_household_sensor_info) - - # Direct Consumption - direct_consumption_household_sensor_info = SensorInfo(name="DirectConsumptionHousehold", device_class="power", unique_id="gridbox_direct_consumption_household", device=device_info, unit_of_measurement="W") - direct_consumption_household_settings = Settings(mqtt=mqtt_settings, entity=direct_consumption_household_sensor_info) - - direct_consumption_heatpump_sensor_info = SensorInfo(name="DirectConsumptionHeatPump", device_class="power", unique_id="gridbox_direct_consumption_heatpump", device=device_info, unit_of_measurement="W") - direct_consumption_heatpump_settings = Settings(mqtt=mqtt_settings, entity=direct_consumption_heatpump_sensor_info) - - direct_consumption_rate_sensor_info = SensorInfo(name="DirectConsumptionRate", device_class="power_factor", unique_id="gridbox_direct_consumption_rate", device=device_info, unit_of_measurement="%") - direct_consumption_rate_settings = Settings(mqtt=mqtt_settings, entity=direct_consumption_rate_sensor_info) - - - # Self Consumption - self_supply_sensor_info = SensorInfo(name="SelfSupply", device_class="power", unique_id="gridbox_self_supply", device=device_info, unit_of_measurement="W") - self_supply_settings = Settings(mqtt=mqtt_settings, entity=self_supply_sensor_info) - - self_consumption_rate_sensor_info = SensorInfo(name="SelfConsumptionRate", device_class="power_factor", unique_id="gridbox_self_consumption_rate", device=device_info, unit_of_measurement="%") - self_consumption_rate_settings = Settings(mqtt=mqtt_settings, entity=self_consumption_rate_sensor_info) - - self_sufficiency_rate_sensor_info = SensorInfo(name="SelfSufficiencyRate", device_class="power_factor", unique_id="gridbox_self_sufficiency_rate", device=device_info, unit_of_measurement="%") - self_sufficiency_rate_settings = Settings(mqtt=mqtt_settings, entity=self_sufficiency_rate_sensor_info) - - - # Battery Section - battery_sensor_info_sum = SensorInfo(name="Battery Sum Level", device_class="battery", unique_id="gridbox_battery_sum", device=device_info, unit_of_measurement="%") - battery_settings_sum = Settings(mqtt=mqtt_settings, entity=battery_sensor_info_sum) - - battery_sensor_capacity_sum = SensorInfo(name="Battery Sum Capacity", device_class="energy", unique_id="gridbox_battery_level_sum", device=device_info, unit_of_measurement="Wh") - battery_settings_capacity_sum = Settings(mqtt=mqtt_settings, entity=battery_sensor_capacity_sum) - - battery_sensor_power_sum = SensorInfo(name="Battery Sum Power", device_class="battery", unique_id="gridbox_battery_power_sum", device=device_info, unit_of_measurement="W") - battery_settings_power_sum = Settings(mqtt=mqtt_settings, entity=battery_sensor_power_sum) - - # Instantiate the sensor - production_sensor = Sensor(production_settings) - grid_sensor = Sensor(grid_settings) - photovoltaic_sensor = Sensor(photovoltaic_settings) - - # Battery sum - battery_sum = Battery(mqtt_settings, device_info, "sum", "") - - # Consumption - consumption_household_sensor = Sensor(consumption_household_settings) - total_consumption_household_sensor = Sensor(total_consumption_household_settings) - direct_consumption_household_sensor = Sensor(direct_consumption_household_settings) - direct_consumtion_heatpump_sensor = Sensor(direct_consumption_heatpump_settings) - direct_consumtion_rate_sensor = Sensor(direct_consumption_rate_settings) - - self_supply_sensor = Sensor(self_supply_settings) - self_consumtion_rate_sensor = Sensor(self_consumption_rate_settings) - + mqtt_settings = Settings.MQTT( + host=mqtt_server, username=mqtt_user, password=mqtt_pw) + viessmann_gridbox_connector = HAViessmannGridboxConnector(mqtt_settings) gridboxConnector = GridboxConnector(data) while True: measurement = gridboxConnector.retrieve_live_data() + viessmann_gridbox_connector.update_sensors(measurement) if one_time_print: print(measurement) one_time_print = False - if "production" in measurement: - production_sensor.set_state(measurement["production"]) - if "grid" in measurement: - grid_sensor.set_state(measurement["grid"]) - if "photovoltaic" in measurement: - photovoltaic_sensor.set_state(measurement["photovoltaic"]) - if "consumption" in measurement: - consumption_household_sensor.set_state(measurement["consumption"]) - if "totalConsumption" in measurement: - total_consumption_household_sensor.set_state(measurement["totalConsumption"]) - if "directConsumptionHousehold" in measurement: - direct_consumption_household_sensor.set_state(float(measurement["directConsumptionHousehold"])) - if "directConsumptionHeatPump" in measurement: - direct_consumtion_heatpump_sensor.set_state(float(measurement["directConsumptionHeatPump"])) - if "directConsumptionRate" in measurement: - direct_consumtion_rate_sensor.set_state(float(measurement["directConsumptionRate"])*100) - - - if "selfSupply" in measurement: - self_supply_sensor.set_state(float(measurement["selfSupply"])) - if "selfConsumptionRate" in measurement: - self_consumtion_rate_sensor.set_state(float(measurement["selfConsumptionRate"])*100) - if "selfSufficiencyRate" in measurement: - self_consumtion_rate_sensor.set_state(float(measurement["selfSufficiencyRate"])*100) - - - if "battery" in measurement: - state_of_charge = float(measurement["battery"]["stateOfCharge"])*100 - capacity = float(measurement["battery"]["capacity"]) - power = float(measurement["battery"]["power"]) - remaining_charge = float(measurement["battery"]["remainingCharge"]) - battery_sum.set_values(state_of_charge, capacity, power, remaining_charge) - if "batteries" in measurement: - for index, battery in enumerate(measurement["batteries"]): - appliance_id = battery["applianceID"] - if appliance_id not in battery_dict: - battery_dict[appliance_id] = Battery(mqtt_settings, device_info, f"{index}", appliance_id) - battery = battery_dict[appliance_id] - state_of_charge = float(measurement["battery"]["stateOfCharge"])*100 - capacity = float(measurement["battery"]["capacity"]) - power = float(measurement["battery"]["power"]) - remaining_charge = float(measurement["battery"]["remainingCharge"]) - battery.set_values(state_of_charge, capacity, power, remaining_charge) # Wait until fetch new values in seconds time.sleep(WAIT) diff --git a/GridboxConnectorAddon-dev/GridboxConnector/ha_viessmann_battery.py b/GridboxConnectorAddon-dev/GridboxConnector/ha_viessmann_battery.py new file mode 100644 index 0000000..4e4430f --- /dev/null +++ b/GridboxConnectorAddon-dev/GridboxConnector/ha_viessmann_battery.py @@ -0,0 +1,62 @@ +from ha_mqtt_discoverable.sensors import Sensor, SensorInfo +from ha_mqtt_discoverable import Settings, DeviceInfo + + +class HAViessmannBattery: + """ +The Battery class represents a battery with associated sensors for level, capacity, power, and remaining charge. Each sensor is created as an MQTT entity with its own SensorInfo and Settings. + +Attributes: + id (str): The unique ID of the battery. + name (str): The name of the battery. + device_info (DeviceInfo): The device information of the battery. + mqtt_settings (Settings.MQTT): The MQTT settings for the sensors. + battery_level (Sensor): The sensor for the battery level. + battery_capacity (Sensor): The sensor for the battery capacity. + battery_power (Sensor): The sensor for the battery power. + battery_remaining_charge (Sensor): The sensor for the remaining battery charge. + +Methods: + get_name(): Returns the name of the battery. + set_states(level, capacity, power, remaining_charge): Sets the states of the four sensors. +""" + + def __init__(self, mqtt_settings, device_info, name, id): + self.id: str = id + self.name: str = name + self.device_info: DeviceInfo = device_info + self.mqtt_settings: Settings.MQTT = mqtt_settings + + self.battery_sensor_info = SensorInfo( + name=f"Battery {name} Level", device_class="battery", unique_id=f"gridbox_battery_{name}", device=device_info, unit_of_measurement="%") + self.battery_settings = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_info) + self.battery_level = Sensor(self.battery_settings) + + self.battery_sensor_capacity = SensorInfo( + name=f"Battery {name} Capacity", device_class="energy", unique_id=f"gridbox_battery_level_{name}", device=device_info, unit_of_measurement="Wh") + self.battery_settings_capacity = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_capacity) + self.battery_capacity = Sensor(self.battery_settings_capacity) + + self.battery_sensor_power = SensorInfo( + name=f"Battery {name} Power", device_class="battery", unique_id=f"gridbox_battery_power_{name}", device=device_info, unit_of_measurement="W") + self.battery_settings_power = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_power) + self.battery_power = Sensor(self.battery_settings_power) + + self.battery_sensor_remaining_charge = SensorInfo( + name=f"Battery {name} Remaining Charge", device_class="energy", unique_id=f"gridbox_remaining_charge_{name}", device=device_info, unit_of_measurement="Wh") + self.battery_settings_remaining_charge = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_remaining_charge) + self.battery_remaining_charge = Sensor( + self.battery_settings_remaining_charge) + + def get_name(self): + return self.name + + def set_states(self, level, capacity, power, remaining_charge): + self.battery_level.set_state(level) + self.battery_capacity.set_state(capacity) + self.battery_power.set_state(power) + self.battery_remaining_charge.set_state(remaining_charge) diff --git a/GridboxConnectorAddon-dev/GridboxConnector/ha_viessmann_gridbox_connector.py b/GridboxConnectorAddon-dev/GridboxConnector/ha_viessmann_gridbox_connector.py new file mode 100644 index 0000000..57c99d8 --- /dev/null +++ b/GridboxConnectorAddon-dev/GridboxConnector/ha_viessmann_gridbox_connector.py @@ -0,0 +1,157 @@ +from ha_mqtt_discoverable import Settings, DeviceInfo +from ha_mqtt_discoverable.sensors import Sensor, SensorInfo +from ha_viessmann_battery import HAViessmannBattery + + +class HAViessmannGridboxConnector: + battery_sensor_dict: dict + mqtt_settings: Settings.MQTT + device_info: DeviceInfo + production_sensor: Sensor + grid_sensor: Sensor + photovoltaic_sensor: Sensor + consumption_household_sensor: Sensor + total_consumption_household_sensor: Sensor + direct_consumption_household_sensor: Sensor + direct_consumtion_heatpump_sensor: Sensor + direct_consumtion_rate_sensor: Sensor + self_supply_sensor: Sensor + self_consumtion_rate_sensor: Sensor + self_sufficiency_rate_sensor: Sensor + battery_sum: HAViessmannBattery + + def __init__(self, mqtt_settings): + self.battery_sensor_dict = {} + self.mqtt_settings = mqtt_settings + self.device_info = DeviceInfo( + name="Viessmann Gridbox", identifiers="viessmann_gridbox", manufacturer="Viessmann", model="Vitocharge 2.0") + + production_sensor_info = SensorInfo(name="Production", device_class="power", + unique_id="gridbox_production", device=self.device_info, unit_of_measurement="W") + production_settings = Settings( + mqtt=mqtt_settings, entity=production_sensor_info) + + grid_sensor_info = SensorInfo(name="Grid", device_class="power", + unique_id="gridbox_grid", device=self.device_info, unit_of_measurement="W") + grid_settings = Settings(mqtt=mqtt_settings, entity=grid_sensor_info) + + photovoltaic_sensor_info = SensorInfo(name="Photovoltaic", device_class="power", + unique_id="gridbox_photovoltaic", device=self.device_info, unit_of_measurement="W") + photovoltaic_settings = Settings( + mqtt=mqtt_settings, entity=photovoltaic_sensor_info) + + # consumption + consumption_household_sensor_info = SensorInfo( + name="Consumption", device_class="power", unique_id="gridbox_consumption_household", device=self.device_info, unit_of_measurement="W") + consumption_household_settings = Settings( + mqtt=mqtt_settings, entity=consumption_household_sensor_info) + + total_consumption_household_sensor_info = SensorInfo( + name="Total Consumption", device_class="power", unique_id="total_consumption_household", device=self.device_info, unit_of_measurement="W") + total_consumption_household_settings = Settings( + mqtt=mqtt_settings, entity=total_consumption_household_sensor_info) + + # Direct Consumption + direct_consumption_household_sensor_info = SensorInfo( + name="DirectConsumptionHousehold", device_class="power", unique_id="gridbox_direct_consumption_household", device=self.device_info, unit_of_measurement="W") + direct_consumption_household_settings = Settings( + mqtt=mqtt_settings, entity=direct_consumption_household_sensor_info) + + direct_consumption_heatpump_sensor_info = SensorInfo( + name="DirectConsumptionHeatPump", device_class="power", unique_id="gridbox_direct_consumption_heatpump", device=self.device_info, unit_of_measurement="W") + direct_consumption_heatpump_settings = Settings( + mqtt=mqtt_settings, entity=direct_consumption_heatpump_sensor_info) + + direct_consumption_rate_sensor_info = SensorInfo( + name="DirectConsumptionRate", device_class="power_factor", unique_id="gridbox_direct_consumption_rate", device=self.device_info, unit_of_measurement="%") + direct_consumption_rate_settings = Settings( + mqtt=mqtt_settings, entity=direct_consumption_rate_sensor_info) + + # Self Consumption + self_supply_sensor_info = SensorInfo(name="SelfSupply", device_class="power", + unique_id="gridbox_self_supply", device=self.device_info, unit_of_measurement="W") + self_supply_settings = Settings( + mqtt=mqtt_settings, entity=self_supply_sensor_info) + + self_consumption_rate_sensor_info = SensorInfo( + name="SelfConsumptionRate", device_class="power_factor", unique_id="gridbox_self_consumption_rate", device=self.device_info, unit_of_measurement="%") + self_consumption_rate_settings = Settings( + mqtt=mqtt_settings, entity=self_consumption_rate_sensor_info) + + self_sufficiency_rate_sensor_info = SensorInfo( + name="SelfSufficiencyRate", device_class="power_factor", unique_id="gridbox_self_sufficiency_rate", device=self.device_info, unit_of_measurement="%") + self_sufficiency_rate_settings = Settings( + mqtt=mqtt_settings, entity=self_sufficiency_rate_sensor_info) + + # Instantiate the sensors + + self.production_sensor = Sensor(production_settings) + self.grid_sensor = Sensor(grid_settings) + self.photovoltaic_sensor = Sensor(photovoltaic_settings) + + # Battery sum + self.battery_sum = HAViessmannBattery( + mqtt_settings, self.device_info, "sum", "") + + # Consumption + self.consumption_household_sensor = Sensor( + consumption_household_settings) + self.total_consumption_household_sensor = Sensor( + total_consumption_household_settings) + self.direct_consumption_household_sensor = Sensor( + direct_consumption_household_settings) + self.direct_consumtion_heatpump_sensor = Sensor( + direct_consumption_heatpump_settings) + self.direct_consumtion_rate_sensor = Sensor( + direct_consumption_rate_settings) + + self.self_supply_sensor = Sensor(self_supply_settings) + self.self_consumtion_rate_sensor = Sensor( + self_consumption_rate_settings) + self.self_sufficiency_rate_sensor = Sensor( + self_sufficiency_rate_settings) + + def update_sensors(self, measurement: dict): + if "production" in measurement: + self.production_sensor.set_state(measurement.get("production", "")) + if "grid" in measurement: + self.grid_sensor.set_state(measurement.get("grid", "")) + if "photovoltaic" in measurement: + self.photovoltaic_sensor.set_state(measurement.get("photovoltaic", "")) + if "consumption" in measurement: + self.consumption_household_sensor.set_state(measurement.get("consumption", "")) + if "totalConsumption" in measurement: + self.total_consumption_household_sensor.set_state(measurement.get("totalConsumption", "")) + if "directConsumptionHousehold" in measurement: + self.direct_consumption_household_sensor.set_state(float(measurement.get("directConsumptionHousehold", "0"))) + if "directConsumptionHeatPump" in measurement: + self.direct_consumtion_heatpump_sensor.set_state(float(measurement.get("directConsumptionHeatPump", "0"))) + if "directConsumptionRate" in measurement: + self.direct_consumtion_rate_sensor.set_state(float(measurement.get("directConsumptionRate", "0"))*100) + + if "selfSupply" in measurement: + self.self_supply_sensor.set_state(float(measurement.get("selfSupply", ""))) + if "selfConsumptionRate" in measurement: + self.self_consumtion_rate_sensor.set_state(float(measurement.get("selfConsumptionRate", "0"))*100) + if "selfSufficiencyRate" in measurement: + self.self_sufficiency_rate_sensor.set_state(float(measurement.get("selfSufficiencyRate", "0"))*100) + + if "battery" in measurement: + battery: dict = measurement.get("battery", {}) + state_of_charge = float(battery.get("stateOfCharge", "0"))*100 + capacity = float(battery.get("capacity", "0")) + power = float(battery.get("power", "0")) + remaining_charge = float(battery.get("remainingCharge", "0")) + self.battery_sum.set_states(state_of_charge, capacity, power, remaining_charge) + if "batteries" in measurement: + batteries: list = measurement.get("batteries", []) + for index, battery in enumerate(batteries): + appliance_id = battery.get("applianceID", "") + if appliance_id not in self.battery_sensor_dict: + self.battery_sensor_dict[appliance_id] = HAViessmannBattery(self.mqtt_settings, self.device_info, f"{index+1}", appliance_id) + battery_sensor = self.battery_sensor_dict[appliance_id] + state_of_charge = float(battery.get("stateOfCharge", "0"))*100 + capacity = float(battery.get("capacity", "0")) + power = float(battery.get("power", "0")) + remaining_charge = float(battery.get("remainingCharge", "0")) + battery_sensor.set_states(state_of_charge, capacity, power, remaining_charge) diff --git a/GridboxConnectorAddon-dev/GridboxConnector/main_test.py b/GridboxConnectorAddon-dev/GridboxConnector/main_test.py new file mode 100644 index 0000000..2fad74d --- /dev/null +++ b/GridboxConnectorAddon-dev/GridboxConnector/main_test.py @@ -0,0 +1,61 @@ +import unittest +from unittest.mock import Mock, patch +from gridbox_connector import GridboxConnector +import json +from ha_mqtt_discoverable import Settings +from ha_viessmann_gridbox_connector import HAViessmannGridboxConnector +from paho.mqtt.client import MQTT_ERR_SUCCESS +from ha_mqtt_discoverable.sensors import Sensor + +mock_data = "{'batteries': [{'applianceID': '97af25d0-3791-48cc-857c-14aaac749267', 'capacity': 10000, 'nominalCapacity': 10000, 'power': -853, 'remainingCharge': 7700, 'stateOfCharge': 0.77}], 'battery': {'capacity': 10000, 'nominalCapacity': 10000, 'power': -853, 'remainingCharge': 7700, 'stateOfCharge': 0.77}, 'consumption': 600, 'directConsumption': 600, 'directConsumptionEV': 0, 'directConsumptionHeatPump': 0, 'directConsumptionHeater': 0, 'directConsumptionHousehold': 600, 'directConsumptionRate': 0.3968253968253968, 'grid': -59, 'gridMeterReadingNegative': 14081760000, 'gridMeterReadingPositive': 7393320000, 'measuredAt': '2024-05-08T09:42:18Z', 'photovoltaic': 1512, 'production': 1512, 'selfConsumption': 1453, 'selfConsumptionRate': 0.9609788359788359, 'selfSufficiencyRate': 1, 'selfSupply': 600, 'totalConsumption': 600}" + + +class TestGridboxConnectorMethods(unittest.TestCase): + + @patch('paho.mqtt.client.Client') + @patch.object(GridboxConnector, 'init_auth', return_value=None) + @patch.object(GridboxConnector, '__init__', return_value=None) + @patch.object(GridboxConnector, 'retrieve_live_data') + def test_main(self, mock_retrieve_live_data, mock_init, mock_init_auth,mock_mqtt_client): + # Load mock data from JSON file + with open('tests/mock_data/mock_data_with_batteries.json') as f: + mock_data = json.load(f) + mock_mqtt_client.return_value.connect.return_value = MQTT_ERR_SUCCESS + mock_retrieve_live_data.return_value = mock_data + # Create an instance of the class + gridbox_connector = GridboxConnector(None) + + # Call the function + result = gridbox_connector.retrieve_live_data() + + # Assert the function was called once + mock_retrieve_live_data.assert_called_once() + + # Assert the function returned the mock value + self.assertEqual(result, mock_data) + mqtt_server = "mqtt_server" + mqtt_user = "mqtt_user" + mqtt_pw = "mqtt_pw" + mqtt_settings = Settings.MQTT( + host=mqtt_server, username=mqtt_user, password=mqtt_pw) + viessmann_gridbox_connector = HAViessmannGridboxConnector( + mqtt_settings) + + with patch.object(viessmann_gridbox_connector.self_supply_sensor, 'set_state') as mock_self_supply_sensor, \ + patch.object(viessmann_gridbox_connector.self_consumtion_rate_sensor, 'set_state') as mock_self_consumtion_rate_sensor, \ + patch.object(viessmann_gridbox_connector.consumption_household_sensor, 'set_state') as mock_consumption_household_sensor, \ + patch.object(viessmann_gridbox_connector.direct_consumption_household_sensor, 'set_state') as mock_direct_consumption_household_sensor, \ + patch.object(viessmann_gridbox_connector.direct_consumtion_heatpump_sensor, 'set_state') as mock_direct_consumtion_heatpump_sensor, \ + patch.object(viessmann_gridbox_connector.direct_consumtion_rate_sensor, 'set_state') as mock_direct_consumtion_rate_sensor, \ + patch.object(viessmann_gridbox_connector.self_sufficiency_rate_sensor, 'set_state') as mock_self_sufficiency_rate_sensor: + viessmann_gridbox_connector.update_sensors(result) + mock_self_supply_sensor.assert_called_once_with(600.0) + mock_self_consumtion_rate_sensor.assert_called_once_with(96.09788359788359) + mock_consumption_household_sensor.assert_called_once_with(600) + mock_direct_consumption_household_sensor.assert_called_once_with(600.0) + mock_direct_consumtion_heatpump_sensor.assert_called_once_with(0.0) + mock_direct_consumtion_rate_sensor.assert_called_once_with(39.682539682539684) + mock_self_sufficiency_rate_sensor.assert_called_once_with(100.0) + +if __name__ == '__main__': + unittest.main() diff --git a/GridboxConnectorAddon-dev/GridboxConnector/requirements.txt b/GridboxConnectorAddon-dev/GridboxConnector/requirements.txt index 4f6a96a..1155fcc 100644 --- a/GridboxConnectorAddon-dev/GridboxConnector/requirements.txt +++ b/GridboxConnectorAddon-dev/GridboxConnector/requirements.txt @@ -1,3 +1,3 @@ ha-mqtt-discoverable==0.13.1 requests==2.31.0 -viessmann-gridbox-connector==1.0.1 +viessmann-gridbox-connector==1.0.2 diff --git a/GridboxConnectorAddon-dev/GridboxConnector/tests/mock_data/mock_data_with_batteries.json b/GridboxConnectorAddon-dev/GridboxConnector/tests/mock_data/mock_data_with_batteries.json new file mode 100644 index 0000000..566ffdf --- /dev/null +++ b/GridboxConnectorAddon-dev/GridboxConnector/tests/mock_data/mock_data_with_batteries.json @@ -0,0 +1,37 @@ +{ + "batteries": [ + { + "applianceID": "97af25d0-3791-48cc-857c-14aaac749267", + "capacity": 10000, + "nominalCapacity": 10000, + "power": -853, + "remainingCharge": 7700, + "stateOfCharge": 0.77 + } + ], + "battery": { + "capacity": 10000, + "nominalCapacity": 10000, + "power": -853, + "remainingCharge": 7700, + "stateOfCharge": 0.77 + }, + "consumption": 600, + "directConsumption": 600, + "directConsumptionEV": 0, + "directConsumptionHeatPump": 0, + "directConsumptionHeater": 0, + "directConsumptionHousehold": 600, + "directConsumptionRate": 0.3968253968253968, + "grid": -59, + "gridMeterReadingNegative": 14081760000, + "gridMeterReadingPositive": 7393320000, + "measuredAt": "2024-05-08T09: 42: 18Z", + "photovoltaic": 1512, + "production": 1512, + "selfConsumption": 1453, + "selfConsumptionRate": 0.9609788359788359, + "selfSufficiencyRate": 1, + "selfSupply": 600, + "totalConsumption": 600 +} diff --git a/GridboxConnectorAddon-dev/README.md b/GridboxConnectorAddon-dev/README.md index 13cfb31..0e1a9f7 100644 --- a/GridboxConnectorAddon-dev/README.md +++ b/GridboxConnectorAddon-dev/README.md @@ -1,4 +1,4 @@ -# Viessmann Gridbox Add-on: Gridbox Connector add-on +# Viessmann Gridbox Connector **Not an Official Viessmann Addon** _Fetch live data from your Viessmann Gridbox_ @@ -15,7 +15,12 @@ _Fetch live data from your Viessmann Gridbox_ # Supported Values The Overview splitted in PV and Battery -## Battery +## Battery Summery +* power +* capacity +* stateOfCharge + +## Each Battery * power * capacity * stateOfCharge diff --git a/GridboxConnectorAddon-dev/cloudSettings.json b/GridboxConnectorAddon-dev/cloudSettings.json index 1febb31..93d420f 100644 --- a/GridboxConnectorAddon-dev/cloudSettings.json +++ b/GridboxConnectorAddon-dev/cloudSettings.json @@ -1,11 +1,11 @@ { - "version":"1.9.11", - "urls": { - "login":"https://gridx.eu.auth0.com/oauth/token", - "gateways":"https://api.gridx.de/gateways", - "live":"https://api.gridx.de/systems/{}/live" - }, - "login":{ + "version": "1.10.2", + "urls": { + "login": "https://gridx.eu.auth0.com/oauth/token", + "gateways": "https://api.gridx.de/gateways", + "live": "https://api.gridx.de/systems/{}/live" + }, + "login": { "grant_type": "http://auth0.com/oauth/grant-type/password-realm", "username": "username", "password": "password", @@ -13,5 +13,5 @@ "client_id": "oZpr934Ikn8OZOHTJEcrgXkjio0I0Q7b", "scope": "email openid", "realm": "viessmann-authentication-db" -} } +} \ No newline at end of file diff --git a/GridboxConnectorAddon-dev/config.yaml b/GridboxConnectorAddon-dev/config.yaml index 97e0480..23c7f42 100644 --- a/GridboxConnectorAddon-dev/config.yaml +++ b/GridboxConnectorAddon-dev/config.yaml @@ -1,9 +1,9 @@ # https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config name: Viessmann Gridbox Connector (dev) -version: "1.9.11" +version: "1.10.2" slug: "gridbox_connector_dev" description: Development version of Viessmann Gridbox Connector -url: "https://github.com/unl0ck/homeassistant-addon-viessmann-gridbox/tree/main/GridboxConnectorAddon" +url: "https://github.com/unl0ck/homeassistant-addon-viessmann-gridbox/tree/main/GridboxConnectorAddon-dev" arch: - armhf - armv7 @@ -29,5 +29,5 @@ schema: OverrideMqttPw: password? OverrideMqttServer: str? OverrideMqttPort: int? -image: ghcr.io/unl0ck/homeassistant-addon-viessmann-gridbox-{arch} +image: ghcr.io/unl0ck/homeassistant-addon-viessmann-gridbox-dev-{arch} stage: experimental diff --git a/GridboxConnectorAddon-dev/rootfs/share/cloudSettings.json b/GridboxConnectorAddon-dev/rootfs/share/cloudSettings.json index 7902744..93d420f 100644 --- a/GridboxConnectorAddon-dev/rootfs/share/cloudSettings.json +++ b/GridboxConnectorAddon-dev/rootfs/share/cloudSettings.json @@ -1,16 +1,17 @@ { - "urls": { - "login":"https://gridx.eu.auth0.com/oauth/token", - "gateways":"https://api.gridx.de/gateways", - "live":"https://api.gridx.de/systems/{}/live" - }, - "login":{ - "grant_type":"http://auth0.com/oauth/grant-type/password-realm", - "username":"email", - "password":"password", - "audience":"my.gridx", - "client_id":"oZpr934Ikn8OZOHTJEcrgXkjio0I0Q7b", - "scope":"email openid", - "realm":"viessmann-authentication-db" - } - } \ No newline at end of file + "version": "1.10.2", + "urls": { + "login": "https://gridx.eu.auth0.com/oauth/token", + "gateways": "https://api.gridx.de/gateways", + "live": "https://api.gridx.de/systems/{}/live" + }, + "login": { + "grant_type": "http://auth0.com/oauth/grant-type/password-realm", + "username": "username", + "password": "password", + "audience": "my.gridx", + "client_id": "oZpr934Ikn8OZOHTJEcrgXkjio0I0Q7b", + "scope": "email openid", + "realm": "viessmann-authentication-db" + } +} \ No newline at end of file diff --git a/GridboxConnectorAddon-experimental/CHANGELOG.md b/GridboxConnectorAddon-experimental/CHANGELOG.md new file mode 100644 index 0000000..591f342 --- /dev/null +++ b/GridboxConnectorAddon-experimental/CHANGELOG.md @@ -0,0 +1,181 @@ + + +## 1.11.0 + +### Added + +- Added S6-overlay + +## 1.10.2 + +## Added + +- Added new sensor `directConsumptionHousehold` and `directConsumptionHeatPump` to show the direct consumption of the household +- Added new sensor `totalConsumption` to show the total consumption of the household +- Added Classes for the sensor to start with unit tests + +## Fixed + +- Fixed the issue with the battery sum sensor +- Fixed the issue with the battery sum appliance id +- Fixed the issue with each battery show now correct values + +## 1.9.12 + +## Fixed + +- Fixed Battery Sum set_state + +## 1.9.11 + +## Fixed + +- Fixed Battery Sum ApplianceID + +## 1.9.10 + +## Fixed + +- Revert to 1.5.0 maybe issue with Battery refactor code + +## 1.9.9 + +### Added + +- Consumption Sensor +- Total Consumption Sensor + +### Fixed + +- Fixed version number +- Fixed copy script from dev to main +- Fixed config.yml + +## 1.5.0 + +### Added + +- Consumption Sensor +- Total Consumption Sensor + +### Fixed + +- set Value only if available + +## 1.4.5 + +### Fixed + +- Code issue + +## 1.4.4 + +### Added + +- mqtt settings + +## 1.4.3 + +### Fixed + +- Code issue + +## 1.4.2 + +### Fixed + +- Versionnumber + +## 1.4.0 + +### Added + +- Sensor directConsumptionHousehold +- Sensor directConsumptionHeatPump +- Use py-lib connector + +## 1.3.0 + +### Fixed + +- wrong code (never use github online editor) + +### Added + +- add Battery Power + +## 1.2.0 + +### Fixed + +- fixed casting battery stateOfCharge + +### Added + +- battery capacity + +## 1.1.3 + +### Fixed + +- use correct battery information + +## 1.1.2 + +- added Vendor + +## 1.1.1 + +### Fixed + +- use correct battery sensor_info + +## 1.1.0 + +- Start with Battery support + +## 1.0.10 + +- fixed python issue + +## 1.0.9 + +- added one time print of data + +## 1.0.8 + +- added dict check + +## 1.0.7 + +- added delay if response is error + +## 1.0.6 + +- fixed multiple generate id_token + +## 1.0.5 + +- added more logs + +## 1.0.4 + +- removed version string in code + +## 1.0.3 + +- added version string + +## 1.0.2 + +- added print to find out why not fetch id_token + +## 1.0.1 + +- fixed refresh Auth Token +- Worked on the Documentation + +## 1.0.0 + +- Initial release +- Added Mqtt Device Discovery diff --git a/GridboxConnectorAddon-experimental/DOCS.md b/GridboxConnectorAddon-experimental/DOCS.md new file mode 100644 index 0000000..b3bbfa1 --- /dev/null +++ b/GridboxConnectorAddon-experimental/DOCS.md @@ -0,0 +1,13 @@ +# Home Assistant Add-on: GridboxConnector +Fetch your Energy data from the Viessmann Gridbox Cloud +## How to use + +### Configuration +Enter your Gridbox Credentials in the Configuration +use your credentials from the Viessmann **myGridbox** App or from the Viessmann Gridbox Webseite https://mygridbox.viessmann.com/login +```yml +username: email +password: password +wait_time: timeout when will refresh +``` +_Remember you have to restart the Addon after changed the Credentials_ diff --git a/GridboxConnectorAddon-experimental/Dockerfile b/GridboxConnectorAddon-experimental/Dockerfile new file mode 100644 index 0000000..8fe5814 --- /dev/null +++ b/GridboxConnectorAddon-experimental/Dockerfile @@ -0,0 +1,27 @@ +# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-dockerfile +ARG BUILD_FROM +FROM $BUILD_FROM +LABEL org.opencontainers.image.source https://github.com/unl0ck/homeassistant-addon-viessmann-gridbox +RUN \ + apk add --no-cache \ + python3 py3-pip +RUN ln -sf python3 /usr/bin/python +COPY rootfs / +#WORKDIR /data + +# Execute during the build of the image +ARG TEMPIO_VERSION BUILD_ARCH +RUN \ + curl -sSLf -o /usr/bin/tempio \ + "https://github.com/home-assistant/tempio/releases/download/${TEMPIO_VERSION}/tempio_${BUILD_ARCH}" + +# Copy root filesystem +COPY GridboxConnector/ /build/GridboxConnector +COPY cloudSettings.json /data/cloudSettings.json +COPY cloudSettings.json /build/. +WORKDIR /build/GridboxConnector +RUN pip install -r requirements.txt +COPY run.sh /run.sh +RUN chmod a+x /run.sh +COPY rootfs / +#CMD [ "/run.sh" ] diff --git a/GridboxConnectorAddon-experimental/GridboxConnector/__init__.py b/GridboxConnectorAddon-experimental/GridboxConnector/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/GridboxConnectorAddon-experimental/GridboxConnector/__main__.py b/GridboxConnectorAddon-experimental/GridboxConnector/__main__.py new file mode 100644 index 0000000..7ba945e --- /dev/null +++ b/GridboxConnectorAddon-experimental/GridboxConnector/__main__.py @@ -0,0 +1,41 @@ +import os +import json +import time +from gridbox_connector import GridboxConnector +from ha_mqtt_discoverable import Settings +from ha_viessmann_gridbox_connector import HAViessmannGridboxConnector + +if __name__ == '__main__': + f = open('/build/cloudSettings.json') + # returns JSON object as + # a dictionary + data = json.load(f) + f.close() + print("Start Viessmann Connector") + # print(f"====Version {data["version"]}====") + + options_file = open('/data/options.json') + options_json = json.load(options_file) + WAIT = int(options_json["wait_time"]) + USER = os.getenv('USERNAME') + PASSWORD = os.environ.get('PASSWORD') + mqtt_user = os.getenv('MqttUser', "") + mqtt_pw = os.getenv('MqttPw', "") + mqtt_server = os.getenv('MqttServer', "") + mqtt_port = os.getenv('MqttPort', "") + data["login"]["username"] = USER + data["login"]["password"] = PASSWORD + print(data["login"]) + one_time_print = True + mqtt_settings = Settings.MQTT( + host=mqtt_server, username=mqtt_user, password=mqtt_pw) + viessmann_gridbox_connector = HAViessmannGridboxConnector(mqtt_settings) + gridboxConnector = GridboxConnector(data) + while True: + measurement = gridboxConnector.retrieve_live_data() + viessmann_gridbox_connector.update_sensors(measurement) + if one_time_print: + print(measurement) + one_time_print = False + # Wait until fetch new values in seconds + time.sleep(WAIT) diff --git a/GridboxConnectorAddon-experimental/GridboxConnector/ha_viessmann_battery.py b/GridboxConnectorAddon-experimental/GridboxConnector/ha_viessmann_battery.py new file mode 100644 index 0000000..4e4430f --- /dev/null +++ b/GridboxConnectorAddon-experimental/GridboxConnector/ha_viessmann_battery.py @@ -0,0 +1,62 @@ +from ha_mqtt_discoverable.sensors import Sensor, SensorInfo +from ha_mqtt_discoverable import Settings, DeviceInfo + + +class HAViessmannBattery: + """ +The Battery class represents a battery with associated sensors for level, capacity, power, and remaining charge. Each sensor is created as an MQTT entity with its own SensorInfo and Settings. + +Attributes: + id (str): The unique ID of the battery. + name (str): The name of the battery. + device_info (DeviceInfo): The device information of the battery. + mqtt_settings (Settings.MQTT): The MQTT settings for the sensors. + battery_level (Sensor): The sensor for the battery level. + battery_capacity (Sensor): The sensor for the battery capacity. + battery_power (Sensor): The sensor for the battery power. + battery_remaining_charge (Sensor): The sensor for the remaining battery charge. + +Methods: + get_name(): Returns the name of the battery. + set_states(level, capacity, power, remaining_charge): Sets the states of the four sensors. +""" + + def __init__(self, mqtt_settings, device_info, name, id): + self.id: str = id + self.name: str = name + self.device_info: DeviceInfo = device_info + self.mqtt_settings: Settings.MQTT = mqtt_settings + + self.battery_sensor_info = SensorInfo( + name=f"Battery {name} Level", device_class="battery", unique_id=f"gridbox_battery_{name}", device=device_info, unit_of_measurement="%") + self.battery_settings = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_info) + self.battery_level = Sensor(self.battery_settings) + + self.battery_sensor_capacity = SensorInfo( + name=f"Battery {name} Capacity", device_class="energy", unique_id=f"gridbox_battery_level_{name}", device=device_info, unit_of_measurement="Wh") + self.battery_settings_capacity = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_capacity) + self.battery_capacity = Sensor(self.battery_settings_capacity) + + self.battery_sensor_power = SensorInfo( + name=f"Battery {name} Power", device_class="battery", unique_id=f"gridbox_battery_power_{name}", device=device_info, unit_of_measurement="W") + self.battery_settings_power = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_power) + self.battery_power = Sensor(self.battery_settings_power) + + self.battery_sensor_remaining_charge = SensorInfo( + name=f"Battery {name} Remaining Charge", device_class="energy", unique_id=f"gridbox_remaining_charge_{name}", device=device_info, unit_of_measurement="Wh") + self.battery_settings_remaining_charge = Settings( + mqtt=mqtt_settings, entity=self.battery_sensor_remaining_charge) + self.battery_remaining_charge = Sensor( + self.battery_settings_remaining_charge) + + def get_name(self): + return self.name + + def set_states(self, level, capacity, power, remaining_charge): + self.battery_level.set_state(level) + self.battery_capacity.set_state(capacity) + self.battery_power.set_state(power) + self.battery_remaining_charge.set_state(remaining_charge) diff --git a/GridboxConnectorAddon-experimental/GridboxConnector/ha_viessmann_gridbox_connector.py b/GridboxConnectorAddon-experimental/GridboxConnector/ha_viessmann_gridbox_connector.py new file mode 100644 index 0000000..57c99d8 --- /dev/null +++ b/GridboxConnectorAddon-experimental/GridboxConnector/ha_viessmann_gridbox_connector.py @@ -0,0 +1,157 @@ +from ha_mqtt_discoverable import Settings, DeviceInfo +from ha_mqtt_discoverable.sensors import Sensor, SensorInfo +from ha_viessmann_battery import HAViessmannBattery + + +class HAViessmannGridboxConnector: + battery_sensor_dict: dict + mqtt_settings: Settings.MQTT + device_info: DeviceInfo + production_sensor: Sensor + grid_sensor: Sensor + photovoltaic_sensor: Sensor + consumption_household_sensor: Sensor + total_consumption_household_sensor: Sensor + direct_consumption_household_sensor: Sensor + direct_consumtion_heatpump_sensor: Sensor + direct_consumtion_rate_sensor: Sensor + self_supply_sensor: Sensor + self_consumtion_rate_sensor: Sensor + self_sufficiency_rate_sensor: Sensor + battery_sum: HAViessmannBattery + + def __init__(self, mqtt_settings): + self.battery_sensor_dict = {} + self.mqtt_settings = mqtt_settings + self.device_info = DeviceInfo( + name="Viessmann Gridbox", identifiers="viessmann_gridbox", manufacturer="Viessmann", model="Vitocharge 2.0") + + production_sensor_info = SensorInfo(name="Production", device_class="power", + unique_id="gridbox_production", device=self.device_info, unit_of_measurement="W") + production_settings = Settings( + mqtt=mqtt_settings, entity=production_sensor_info) + + grid_sensor_info = SensorInfo(name="Grid", device_class="power", + unique_id="gridbox_grid", device=self.device_info, unit_of_measurement="W") + grid_settings = Settings(mqtt=mqtt_settings, entity=grid_sensor_info) + + photovoltaic_sensor_info = SensorInfo(name="Photovoltaic", device_class="power", + unique_id="gridbox_photovoltaic", device=self.device_info, unit_of_measurement="W") + photovoltaic_settings = Settings( + mqtt=mqtt_settings, entity=photovoltaic_sensor_info) + + # consumption + consumption_household_sensor_info = SensorInfo( + name="Consumption", device_class="power", unique_id="gridbox_consumption_household", device=self.device_info, unit_of_measurement="W") + consumption_household_settings = Settings( + mqtt=mqtt_settings, entity=consumption_household_sensor_info) + + total_consumption_household_sensor_info = SensorInfo( + name="Total Consumption", device_class="power", unique_id="total_consumption_household", device=self.device_info, unit_of_measurement="W") + total_consumption_household_settings = Settings( + mqtt=mqtt_settings, entity=total_consumption_household_sensor_info) + + # Direct Consumption + direct_consumption_household_sensor_info = SensorInfo( + name="DirectConsumptionHousehold", device_class="power", unique_id="gridbox_direct_consumption_household", device=self.device_info, unit_of_measurement="W") + direct_consumption_household_settings = Settings( + mqtt=mqtt_settings, entity=direct_consumption_household_sensor_info) + + direct_consumption_heatpump_sensor_info = SensorInfo( + name="DirectConsumptionHeatPump", device_class="power", unique_id="gridbox_direct_consumption_heatpump", device=self.device_info, unit_of_measurement="W") + direct_consumption_heatpump_settings = Settings( + mqtt=mqtt_settings, entity=direct_consumption_heatpump_sensor_info) + + direct_consumption_rate_sensor_info = SensorInfo( + name="DirectConsumptionRate", device_class="power_factor", unique_id="gridbox_direct_consumption_rate", device=self.device_info, unit_of_measurement="%") + direct_consumption_rate_settings = Settings( + mqtt=mqtt_settings, entity=direct_consumption_rate_sensor_info) + + # Self Consumption + self_supply_sensor_info = SensorInfo(name="SelfSupply", device_class="power", + unique_id="gridbox_self_supply", device=self.device_info, unit_of_measurement="W") + self_supply_settings = Settings( + mqtt=mqtt_settings, entity=self_supply_sensor_info) + + self_consumption_rate_sensor_info = SensorInfo( + name="SelfConsumptionRate", device_class="power_factor", unique_id="gridbox_self_consumption_rate", device=self.device_info, unit_of_measurement="%") + self_consumption_rate_settings = Settings( + mqtt=mqtt_settings, entity=self_consumption_rate_sensor_info) + + self_sufficiency_rate_sensor_info = SensorInfo( + name="SelfSufficiencyRate", device_class="power_factor", unique_id="gridbox_self_sufficiency_rate", device=self.device_info, unit_of_measurement="%") + self_sufficiency_rate_settings = Settings( + mqtt=mqtt_settings, entity=self_sufficiency_rate_sensor_info) + + # Instantiate the sensors + + self.production_sensor = Sensor(production_settings) + self.grid_sensor = Sensor(grid_settings) + self.photovoltaic_sensor = Sensor(photovoltaic_settings) + + # Battery sum + self.battery_sum = HAViessmannBattery( + mqtt_settings, self.device_info, "sum", "") + + # Consumption + self.consumption_household_sensor = Sensor( + consumption_household_settings) + self.total_consumption_household_sensor = Sensor( + total_consumption_household_settings) + self.direct_consumption_household_sensor = Sensor( + direct_consumption_household_settings) + self.direct_consumtion_heatpump_sensor = Sensor( + direct_consumption_heatpump_settings) + self.direct_consumtion_rate_sensor = Sensor( + direct_consumption_rate_settings) + + self.self_supply_sensor = Sensor(self_supply_settings) + self.self_consumtion_rate_sensor = Sensor( + self_consumption_rate_settings) + self.self_sufficiency_rate_sensor = Sensor( + self_sufficiency_rate_settings) + + def update_sensors(self, measurement: dict): + if "production" in measurement: + self.production_sensor.set_state(measurement.get("production", "")) + if "grid" in measurement: + self.grid_sensor.set_state(measurement.get("grid", "")) + if "photovoltaic" in measurement: + self.photovoltaic_sensor.set_state(measurement.get("photovoltaic", "")) + if "consumption" in measurement: + self.consumption_household_sensor.set_state(measurement.get("consumption", "")) + if "totalConsumption" in measurement: + self.total_consumption_household_sensor.set_state(measurement.get("totalConsumption", "")) + if "directConsumptionHousehold" in measurement: + self.direct_consumption_household_sensor.set_state(float(measurement.get("directConsumptionHousehold", "0"))) + if "directConsumptionHeatPump" in measurement: + self.direct_consumtion_heatpump_sensor.set_state(float(measurement.get("directConsumptionHeatPump", "0"))) + if "directConsumptionRate" in measurement: + self.direct_consumtion_rate_sensor.set_state(float(measurement.get("directConsumptionRate", "0"))*100) + + if "selfSupply" in measurement: + self.self_supply_sensor.set_state(float(measurement.get("selfSupply", ""))) + if "selfConsumptionRate" in measurement: + self.self_consumtion_rate_sensor.set_state(float(measurement.get("selfConsumptionRate", "0"))*100) + if "selfSufficiencyRate" in measurement: + self.self_sufficiency_rate_sensor.set_state(float(measurement.get("selfSufficiencyRate", "0"))*100) + + if "battery" in measurement: + battery: dict = measurement.get("battery", {}) + state_of_charge = float(battery.get("stateOfCharge", "0"))*100 + capacity = float(battery.get("capacity", "0")) + power = float(battery.get("power", "0")) + remaining_charge = float(battery.get("remainingCharge", "0")) + self.battery_sum.set_states(state_of_charge, capacity, power, remaining_charge) + if "batteries" in measurement: + batteries: list = measurement.get("batteries", []) + for index, battery in enumerate(batteries): + appliance_id = battery.get("applianceID", "") + if appliance_id not in self.battery_sensor_dict: + self.battery_sensor_dict[appliance_id] = HAViessmannBattery(self.mqtt_settings, self.device_info, f"{index+1}", appliance_id) + battery_sensor = self.battery_sensor_dict[appliance_id] + state_of_charge = float(battery.get("stateOfCharge", "0"))*100 + capacity = float(battery.get("capacity", "0")) + power = float(battery.get("power", "0")) + remaining_charge = float(battery.get("remainingCharge", "0")) + battery_sensor.set_states(state_of_charge, capacity, power, remaining_charge) diff --git a/GridboxConnectorAddon-experimental/GridboxConnector/main_test.py b/GridboxConnectorAddon-experimental/GridboxConnector/main_test.py new file mode 100644 index 0000000..2fad74d --- /dev/null +++ b/GridboxConnectorAddon-experimental/GridboxConnector/main_test.py @@ -0,0 +1,61 @@ +import unittest +from unittest.mock import Mock, patch +from gridbox_connector import GridboxConnector +import json +from ha_mqtt_discoverable import Settings +from ha_viessmann_gridbox_connector import HAViessmannGridboxConnector +from paho.mqtt.client import MQTT_ERR_SUCCESS +from ha_mqtt_discoverable.sensors import Sensor + +mock_data = "{'batteries': [{'applianceID': '97af25d0-3791-48cc-857c-14aaac749267', 'capacity': 10000, 'nominalCapacity': 10000, 'power': -853, 'remainingCharge': 7700, 'stateOfCharge': 0.77}], 'battery': {'capacity': 10000, 'nominalCapacity': 10000, 'power': -853, 'remainingCharge': 7700, 'stateOfCharge': 0.77}, 'consumption': 600, 'directConsumption': 600, 'directConsumptionEV': 0, 'directConsumptionHeatPump': 0, 'directConsumptionHeater': 0, 'directConsumptionHousehold': 600, 'directConsumptionRate': 0.3968253968253968, 'grid': -59, 'gridMeterReadingNegative': 14081760000, 'gridMeterReadingPositive': 7393320000, 'measuredAt': '2024-05-08T09:42:18Z', 'photovoltaic': 1512, 'production': 1512, 'selfConsumption': 1453, 'selfConsumptionRate': 0.9609788359788359, 'selfSufficiencyRate': 1, 'selfSupply': 600, 'totalConsumption': 600}" + + +class TestGridboxConnectorMethods(unittest.TestCase): + + @patch('paho.mqtt.client.Client') + @patch.object(GridboxConnector, 'init_auth', return_value=None) + @patch.object(GridboxConnector, '__init__', return_value=None) + @patch.object(GridboxConnector, 'retrieve_live_data') + def test_main(self, mock_retrieve_live_data, mock_init, mock_init_auth,mock_mqtt_client): + # Load mock data from JSON file + with open('tests/mock_data/mock_data_with_batteries.json') as f: + mock_data = json.load(f) + mock_mqtt_client.return_value.connect.return_value = MQTT_ERR_SUCCESS + mock_retrieve_live_data.return_value = mock_data + # Create an instance of the class + gridbox_connector = GridboxConnector(None) + + # Call the function + result = gridbox_connector.retrieve_live_data() + + # Assert the function was called once + mock_retrieve_live_data.assert_called_once() + + # Assert the function returned the mock value + self.assertEqual(result, mock_data) + mqtt_server = "mqtt_server" + mqtt_user = "mqtt_user" + mqtt_pw = "mqtt_pw" + mqtt_settings = Settings.MQTT( + host=mqtt_server, username=mqtt_user, password=mqtt_pw) + viessmann_gridbox_connector = HAViessmannGridboxConnector( + mqtt_settings) + + with patch.object(viessmann_gridbox_connector.self_supply_sensor, 'set_state') as mock_self_supply_sensor, \ + patch.object(viessmann_gridbox_connector.self_consumtion_rate_sensor, 'set_state') as mock_self_consumtion_rate_sensor, \ + patch.object(viessmann_gridbox_connector.consumption_household_sensor, 'set_state') as mock_consumption_household_sensor, \ + patch.object(viessmann_gridbox_connector.direct_consumption_household_sensor, 'set_state') as mock_direct_consumption_household_sensor, \ + patch.object(viessmann_gridbox_connector.direct_consumtion_heatpump_sensor, 'set_state') as mock_direct_consumtion_heatpump_sensor, \ + patch.object(viessmann_gridbox_connector.direct_consumtion_rate_sensor, 'set_state') as mock_direct_consumtion_rate_sensor, \ + patch.object(viessmann_gridbox_connector.self_sufficiency_rate_sensor, 'set_state') as mock_self_sufficiency_rate_sensor: + viessmann_gridbox_connector.update_sensors(result) + mock_self_supply_sensor.assert_called_once_with(600.0) + mock_self_consumtion_rate_sensor.assert_called_once_with(96.09788359788359) + mock_consumption_household_sensor.assert_called_once_with(600) + mock_direct_consumption_household_sensor.assert_called_once_with(600.0) + mock_direct_consumtion_heatpump_sensor.assert_called_once_with(0.0) + mock_direct_consumtion_rate_sensor.assert_called_once_with(39.682539682539684) + mock_self_sufficiency_rate_sensor.assert_called_once_with(100.0) + +if __name__ == '__main__': + unittest.main() diff --git a/GridboxConnectorAddon-experimental/GridboxConnector/requirements.txt b/GridboxConnectorAddon-experimental/GridboxConnector/requirements.txt new file mode 100644 index 0000000..1155fcc --- /dev/null +++ b/GridboxConnectorAddon-experimental/GridboxConnector/requirements.txt @@ -0,0 +1,3 @@ +ha-mqtt-discoverable==0.13.1 +requests==2.31.0 +viessmann-gridbox-connector==1.0.2 diff --git a/GridboxConnectorAddon-experimental/GridboxConnector/tests/mock_data/mock_data_with_batteries.json b/GridboxConnectorAddon-experimental/GridboxConnector/tests/mock_data/mock_data_with_batteries.json new file mode 100644 index 0000000..566ffdf --- /dev/null +++ b/GridboxConnectorAddon-experimental/GridboxConnector/tests/mock_data/mock_data_with_batteries.json @@ -0,0 +1,37 @@ +{ + "batteries": [ + { + "applianceID": "97af25d0-3791-48cc-857c-14aaac749267", + "capacity": 10000, + "nominalCapacity": 10000, + "power": -853, + "remainingCharge": 7700, + "stateOfCharge": 0.77 + } + ], + "battery": { + "capacity": 10000, + "nominalCapacity": 10000, + "power": -853, + "remainingCharge": 7700, + "stateOfCharge": 0.77 + }, + "consumption": 600, + "directConsumption": 600, + "directConsumptionEV": 0, + "directConsumptionHeatPump": 0, + "directConsumptionHeater": 0, + "directConsumptionHousehold": 600, + "directConsumptionRate": 0.3968253968253968, + "grid": -59, + "gridMeterReadingNegative": 14081760000, + "gridMeterReadingPositive": 7393320000, + "measuredAt": "2024-05-08T09: 42: 18Z", + "photovoltaic": 1512, + "production": 1512, + "selfConsumption": 1453, + "selfConsumptionRate": 0.9609788359788359, + "selfSufficiencyRate": 1, + "selfSupply": 600, + "totalConsumption": 600 +} diff --git a/GridboxConnectorAddon-experimental/README.md b/GridboxConnectorAddon-experimental/README.md new file mode 100644 index 0000000..0e1a9f7 --- /dev/null +++ b/GridboxConnectorAddon-experimental/README.md @@ -0,0 +1,39 @@ +# Viessmann Gridbox Connector +**Not an Official Viessmann Addon** + +_Fetch live data from your Viessmann Gridbox_ + +![Supports aarch64 Architecture][aarch64-shield] +![Supports amd64 Architecture][amd64-shield] +![Supports armhf Architecture][armhf-shield] +![Supports armv7 Architecture][armv7-shield] + +[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg +[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg +[armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg +[armv7-shield]: https://img.shields.io/badge/armv7-yes-green.svg + +# Supported Values +The Overview splitted in PV and Battery +## Battery Summery +* power +* capacity +* stateOfCharge + +## Each Battery +* power +* capacity +* stateOfCharge + +## Consumption +* production +* grid +* photovoltaic +* consumption +* totalConsumption +* directConsumptionHousehold +* directConsumptionHeatPump +* directConsumptionRate +* selfSupply +* selfConsumptionRate +* selfSufficiencyRate diff --git a/GridboxConnectorAddon-experimental/apparmor.txt b/GridboxConnectorAddon-experimental/apparmor.txt new file mode 100644 index 0000000..e788a6c --- /dev/null +++ b/GridboxConnectorAddon-experimental/apparmor.txt @@ -0,0 +1,57 @@ +#include + +profile example flags=(attach_disconnected,mediate_deleted) { + #include + + # Capabilities + file, + signal (send) set=(kill,term,int,hup,cont), + + # S6-Overlay + /init ix, + /bin/** ix, + /usr/bin/** ix, + /run/{s6,s6-rc*,service}/** ix, + /package/** ix, + /command/** ix, + /etc/services.d/** rwix, + /etc/cont-init.d/** rwix, + /etc/cont-finish.d/** rwix, + /run/{,**} rwk, + /dev/tty rw, + + # Bashio + /usr/lib/bashio/** ix, + /tmp/** rwk, + + # Access to options.json and other files within your addon + /data/** rw, + + # Start new profile for service + /usr/bin/my_program cx -> my_program, + + profile my_program flags=(attach_disconnected,mediate_deleted) { + #include + + # Receive signals from S6-Overlay + signal (receive) peer=*_example, + + # Access to options.json and other files within your addon + /data/** rw, + + # Access to mapped volumes specified in config.json + /share/** rw, + + # Access required for service functionality + # Note: List was built by doing the following: + # 1. Add what is obviously needed based on what is in the script + # 2. Add `complain` as a flag to this profile temporarily and run the addon + # 3. Review the audit log with `journalctl _TRANSPORT="audit" -g 'apparmor="ALLOWED"'` and add other access as needed + # Remember to remove the `complain` flag when you are done + /usr/bin/my_program r, + /bin/bash rix, + /bin/echo ix, + /etc/passwd r, + /dev/tty rw, + } +} \ No newline at end of file diff --git a/GridboxConnectorAddon-experimental/build.yaml b/GridboxConnectorAddon-experimental/build.yaml new file mode 100644 index 0000000..53d0e5c --- /dev/null +++ b/GridboxConnectorAddon-experimental/build.yaml @@ -0,0 +1,13 @@ +# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-dockerfile +build_from: + aarch64: "ghcr.io/home-assistant/aarch64-base-python:3.10-alpine3.16" + amd64: "ghcr.io/home-assistant/amd64-base-python:3.10-alpine3.16" + armhf: "ghcr.io/home-assistant/armhf-base-python:3.10-alpine3.16" + armv7: "ghcr.io/home-assistant/armv7-base-python:3.10-alpine3.16" +labels: + org.opencontainers.image.title: "Viessmann Gridbox Connector (dev)" + org.opencontainers.image.description: "Development of Viessmann Gridbox Connector" + org.opencontainers.image.source: "https://github.com/unl0ck/homeassistant-addon-viessmann-gridbox" + org.opencontainers.image.licenses: "Apache License 2.0" +args: + TEMPIO_VERSION: "2021.09.0" diff --git a/GridboxConnectorAddon-experimental/cloudSettings.json b/GridboxConnectorAddon-experimental/cloudSettings.json new file mode 100644 index 0000000..e38d921 --- /dev/null +++ b/GridboxConnectorAddon-experimental/cloudSettings.json @@ -0,0 +1,17 @@ +{ + "version": "1.11.0", + "urls": { + "login": "https://gridx.eu.auth0.com/oauth/token", + "gateways": "https://api.gridx.de/gateways", + "live": "https://api.gridx.de/systems/{}/live" + }, + "login": { + "grant_type": "http://auth0.com/oauth/grant-type/password-realm", + "username": "username", + "password": "password", + "audience": "my.gridx", + "client_id": "oZpr934Ikn8OZOHTJEcrgXkjio0I0Q7b", + "scope": "email openid", + "realm": "viessmann-authentication-db" + } +} diff --git a/GridboxConnectorAddon-experimental/config.yaml b/GridboxConnectorAddon-experimental/config.yaml new file mode 100644 index 0000000..4dc5499 --- /dev/null +++ b/GridboxConnectorAddon-experimental/config.yaml @@ -0,0 +1,34 @@ +# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config +name: Viessmann Gridbox Connector (experimental) +version: "1.11.0" +slug: "gridbox_connector_experimental" +apparmor: false +description: Development version of Viessmann Gridbox Connector +url: "https://github.com/unl0ck/homeassistant-addon-viessmann-gridbox/tree/main/GridboxConnectorAddon-experimental" +arch: + - armhf + - armv7 + - aarch64 + - amd64 +init: false +codenotary: notary@home-assistant.io +map: + - share:ro +discovery: + - "mqtt" +services: + - "mqtt:need" +options: + username: "email" + password: "password" + wait_time: 60 +schema: + username: str + password: password + wait_time: int + OverrideMqttUser: str? + OverrideMqttPw: password? + OverrideMqttServer: str? + OverrideMqttPort: int? +image: ghcr.io/unl0ck/homeassistant-addon-viessmann-gridbox-experimental-{arch} +stage: experimental diff --git a/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/banner/type b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/banner/type new file mode 100644 index 0000000..3d92b15 --- /dev/null +++ b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/banner/type @@ -0,0 +1 @@ +oneshot \ No newline at end of file diff --git a/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/banner/up b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/banner/up new file mode 100644 index 0000000..1bb9a0c --- /dev/null +++ b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/banner/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/banner.sh \ No newline at end of file diff --git a/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/dependencies.d/banner b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/dependencies.d/banner new file mode 100644 index 0000000..e69de29 diff --git a/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/type b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/type new file mode 100644 index 0000000..1780f9f --- /dev/null +++ b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/type @@ -0,0 +1 @@ +longrun \ No newline at end of file diff --git a/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/up b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/up new file mode 100644 index 0000000..395707e --- /dev/null +++ b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/s6-rc.d/gridboxconnector/up @@ -0,0 +1,19 @@ +#!/usr/bin/with-contenv bashio + +export MqttUser=$(bashio::config 'OverrideMqttUser') +export MqttPw=$(bashio::config 'OverrideMqttPw') +export MqttServer=$(bashio::config 'OverrideMqttServer') +export MqttPort=$(bashio::config 'OverrideMqttPort') + +test "$MqttUser" = "null" && export MqttUser=$(bashio::services "mqtt" "username") +test "$MqttPw" = "null" && export MqttPw=$(bashio::services "mqtt" "password") +test "$MqttServer" = "null" && export MqttServer=$(bashio::services "mqtt" "host") +test "$MqttPort" = "null" && export MqttPort=$(bashio::services "mqtt" "port") +export USERNAME=$(bashio::config 'username') +export PASSWORD=$(bashio::config 'password') +ls -lash /data +cat /data/options.json +cd /build/ +ls -lash +pwd +python GridboxConnector diff --git a/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/scripts/banner.sh b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/scripts/banner.sh new file mode 100644 index 0000000..7a8cae3 --- /dev/null +++ b/GridboxConnectorAddon-experimental/rootfs/etc/s6-overlay/scripts/banner.sh @@ -0,0 +1,37 @@ +#!/usr/bin/with-contenv bashio +# ============================================================================== +# Home Assistant Community Add-on: Base Images +# Displays a simple add-on banner on startup +# ============================================================================== +if bashio::supervisor.ping; then + bashio::log.blue \ + '-----------------------------------------------------------' + bashio::log.blue " Add-on: $(bashio::addon.name)" + bashio::log.blue " $(bashio::addon.description)" + bashio::log.blue \ + '-----------------------------------------------------------' + + bashio::log.blue " Add-on version: $(bashio::addon.version)" + if bashio::var.true "$(bashio::addon.update_available)"; then + bashio::log.magenta ' There is an update available for this add-on!' + bashio::log.magenta \ + " Latest add-on version: $(bashio::addon.version_latest)" + bashio::log.magenta ' Please consider upgrading as soon as possible.' + else + bashio::log.green ' You are running the latest version of this add-on.' + fi + + bashio::log.blue " System: $(bashio::info.operating_system)" \ + " ($(bashio::info.arch) / $(bashio::info.machine))" + bashio::log.blue " Home Assistant Core: $(bashio::info.homeassistant)" + bashio::log.blue " Home Assistant Supervisor: $(bashio::info.supervisor)" + + bashio::log.blue \ + '-----------------------------------------------------------' + bashio::log.blue \ + ' Please, share the above information when looking for help' + bashio::log.blue \ + ' or support in, e.g., GitHub, forums or the Discord chat.' + bashio::log.blue \ + '-----------------------------------------------------------' +fi \ No newline at end of file diff --git a/GridboxConnectorAddon-experimental/rootfs/share/cloudSettings.json b/GridboxConnectorAddon-experimental/rootfs/share/cloudSettings.json new file mode 100644 index 0000000..e38d921 --- /dev/null +++ b/GridboxConnectorAddon-experimental/rootfs/share/cloudSettings.json @@ -0,0 +1,17 @@ +{ + "version": "1.11.0", + "urls": { + "login": "https://gridx.eu.auth0.com/oauth/token", + "gateways": "https://api.gridx.de/gateways", + "live": "https://api.gridx.de/systems/{}/live" + }, + "login": { + "grant_type": "http://auth0.com/oauth/grant-type/password-realm", + "username": "username", + "password": "password", + "audience": "my.gridx", + "client_id": "oZpr934Ikn8OZOHTJEcrgXkjio0I0Q7b", + "scope": "email openid", + "realm": "viessmann-authentication-db" + } +} diff --git a/GridboxConnectorAddon-experimental/run.sh b/GridboxConnectorAddon-experimental/run.sh new file mode 100644 index 0000000..395707e --- /dev/null +++ b/GridboxConnectorAddon-experimental/run.sh @@ -0,0 +1,19 @@ +#!/usr/bin/with-contenv bashio + +export MqttUser=$(bashio::config 'OverrideMqttUser') +export MqttPw=$(bashio::config 'OverrideMqttPw') +export MqttServer=$(bashio::config 'OverrideMqttServer') +export MqttPort=$(bashio::config 'OverrideMqttPort') + +test "$MqttUser" = "null" && export MqttUser=$(bashio::services "mqtt" "username") +test "$MqttPw" = "null" && export MqttPw=$(bashio::services "mqtt" "password") +test "$MqttServer" = "null" && export MqttServer=$(bashio::services "mqtt" "host") +test "$MqttPort" = "null" && export MqttPort=$(bashio::services "mqtt" "port") +export USERNAME=$(bashio::config 'username') +export PASSWORD=$(bashio::config 'password') +ls -lash /data +cat /data/options.json +cd /build/ +ls -lash +pwd +python GridboxConnector diff --git a/GridboxConnectorAddon-experimental/translations/en.yaml b/GridboxConnectorAddon-experimental/translations/en.yaml new file mode 100644 index 0000000..c0b41d0 --- /dev/null +++ b/GridboxConnectorAddon-experimental/translations/en.yaml @@ -0,0 +1,10 @@ +configuration: + username: + name: Username + description: Enter here your email address + password: + name: Password + description: Enter here your Password + wait_time: + name: Wait + description: Set time in seconds how long will wait until fetch new data diff --git a/GridboxConnectorAddon/CHANGELOG.md b/GridboxConnectorAddon/CHANGELOG.md index 89f067a..d20b5e4 100644 --- a/GridboxConnectorAddon/CHANGELOG.md +++ b/GridboxConnectorAddon/CHANGELOG.md @@ -1,4 +1,16 @@ +## 1.9.12 + +## Fixed + +- Fixed Battery Sum set_state + + +## 1.9.11 + +## Fixed + +- Fixed Battery Sum ApplianceID ## 1.9.10 diff --git a/GridboxConnectorAddon/GridboxConnector/__main__.py b/GridboxConnectorAddon/GridboxConnector/__main__.py index b15caec..b72a1e3 100644 --- a/GridboxConnectorAddon/GridboxConnector/__main__.py +++ b/GridboxConnectorAddon/GridboxConnector/__main__.py @@ -4,7 +4,7 @@ from ha_mqtt_discoverable import Settings, DeviceInfo from ha_mqtt_discoverable.sensors import Sensor, SensorInfo from gridbox_connector import GridboxConnector - +from Battery import Battery if __name__ == '__main__': f = open('/build/cloudSettings.json') @@ -29,6 +29,8 @@ print(data["login"]) one_time_print = True + battery_dict = {} + mqtt_settings = Settings.MQTT(host=mqtt_server, username=mqtt_user, password=mqtt_pw) device_info = DeviceInfo(name="Viessmann Gridbox", identifiers="viessmann_gridbox", manufacturer="Viessmann", model="Vitocharge 2.0") @@ -86,10 +88,8 @@ grid_sensor = Sensor(grid_settings) photovoltaic_sensor = Sensor(photovoltaic_settings) - # Battery - battery_sum_level = Sensor(battery_settings_sum) - battery_sum_capacity = Sensor(battery_settings_capacity_sum) - battery_sum_power = Sensor(battery_settings_power_sum) + # Battery sum + battery_sum = Battery(mqtt_settings, device_info, "sum", "") # Consumption consumption_household_sensor = Sensor(consumption_household_settings) @@ -134,8 +134,21 @@ if "battery" in measurement: - battery_sum_level.set_state(float(measurement["battery"]["stateOfCharge"])*100) - battery_sum_capacity.set_state(float(measurement["battery"]["capacity"])) - battery_sum_power.set_state(float(measurement["battery"]["power"])) + state_of_charge = float(measurement["battery"]["stateOfCharge"])*100 + capacity = float(measurement["battery"]["capacity"]) + power = float(measurement["battery"]["power"]) + remaining_charge = float(measurement["battery"]["remainingCharge"]) + battery_sum.set_states(state_of_charge, capacity, power, remaining_charge) + if "batteries" in measurement: + for index, battery in enumerate(measurement["batteries"]): + appliance_id = battery["applianceID"] + if appliance_id not in battery_dict: + battery_dict[appliance_id] = Battery(mqtt_settings, device_info, f"{index+1}", appliance_id) + battery = battery_dict[appliance_id] + state_of_charge = float(measurement["battery"]["stateOfCharge"])*100 + capacity = float(measurement["battery"]["capacity"]) + power = float(measurement["battery"]["power"]) + remaining_charge = float(measurement["battery"]["remainingCharge"]) + battery.set_states(state_of_charge, capacity, power, remaining_charge) # Wait until fetch new values in seconds - time.sleep(WAIT) \ No newline at end of file + time.sleep(WAIT) diff --git a/GridboxConnectorAddon/README.md b/GridboxConnectorAddon/README.md index 13cfb31..0e1a9f7 100644 --- a/GridboxConnectorAddon/README.md +++ b/GridboxConnectorAddon/README.md @@ -1,4 +1,4 @@ -# Viessmann Gridbox Add-on: Gridbox Connector add-on +# Viessmann Gridbox Connector **Not an Official Viessmann Addon** _Fetch live data from your Viessmann Gridbox_ @@ -15,7 +15,12 @@ _Fetch live data from your Viessmann Gridbox_ # Supported Values The Overview splitted in PV and Battery -## Battery +## Battery Summery +* power +* capacity +* stateOfCharge + +## Each Battery * power * capacity * stateOfCharge diff --git a/GridboxConnectorAddon/cloudSettings.json b/GridboxConnectorAddon/cloudSettings.json index aa5b8c4..142a702 100644 --- a/GridboxConnectorAddon/cloudSettings.json +++ b/GridboxConnectorAddon/cloudSettings.json @@ -1,5 +1,5 @@ { - "version":"1.9.10", + "version":"1.9.12", "urls": { "login":"https://gridx.eu.auth0.com/oauth/token", "gateways":"https://api.gridx.de/gateways", diff --git a/GridboxConnectorAddon/config.yaml b/GridboxConnectorAddon/config.yaml index 0764de5..be5f6e1 100644 --- a/GridboxConnectorAddon/config.yaml +++ b/GridboxConnectorAddon/config.yaml @@ -1,6 +1,6 @@ # https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config -name: Viessmann Gridbox Connector add-on -version: "1.9.10" +name: Viessmann Gridbox Connector +version: "1.9.12" slug: "gridbox_connector" description: Fetch your live data from your Viessmann Gridbox url: "https://github.com/unl0ck/homeassistant-addon-viessmann-gridbox/tree/main/GridboxConnectorAddon" diff --git a/README.md b/README.md index 071c053..59a8360 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,25 @@ # Home Assistant Viessmann Gridbox Addons +[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg +[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg +[armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg +[armv7-shield]: https://img.shields.io/badge/armv7-yes-green.svg +![Supports aarch64 Architecture][aarch64-shield] +![Supports amd64 Architecture][amd64-shield] +![Supports armhf Architecture][armhf-shield] +![Supports armv7 Architecture][armv7-shield] + **Not an official Viessmann Addon** +Get your Gridbox Data via MQTT to your Home Assistant Server + [![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Funl0ck%2Fhomeassistant-addon-viessmann-gridbox) ## Add-ons -### [GridboxConnector add-on](./GridboxConnectorAddon) +### [Viessmann Gridbox Connector](./GridboxConnectorAddon) +### [Viessmann Gridbox Connector (Dev)](./GridboxConnectorAddon-dev) + + -![Supports aarch64 Architecture][aarch64-shield] -![Supports amd64 Architecture][amd64-shield] -![Supports armhf Architecture][armhf-shield] -![Supports armv7 Architecture][armv7-shield] -[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg -[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg -[armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg -[armv7-shield]: https://img.shields.io/badge/armv7-yes-green.svg diff --git a/copy_to_release.sh b/copy_to_release.sh index 4c70373..32b91af 100755 --- a/copy_to_release.sh +++ b/copy_to_release.sh @@ -5,4 +5,10 @@ src_dir="GridboxConnectorAddon-dev" target_dir="GridboxConnectorAddon" # Copy all files from source to target directory, excluding config.yml and build.yml -rsync -av --exclude='config.yaml' --exclude='build.yaml' $src_dir/ $target_dir/ \ No newline at end of file +rsync -av --exclude='config.yaml' --exclude='build.yaml' --exclude='__pycache__' --exclude='.pytest_cache' $src_dir/ $target_dir/ +# Read the current version from .bumpversion-dev.toml +current_version=$(jq -r '.version' GridboxConnectorAddon/rootfs/share/cloudSettings.json) + +# Update the version in the config.yaml file +sed -i '' "s/version: \".*\"/version: \"$current_version\"/" GridboxConnectorAddon/config.yaml +