From a5004c5bf7bfe4d47b6604a03e8685212b3c6e23 Mon Sep 17 00:00:00 2001 From: t0bias-r Date: Mon, 4 Mar 2024 08:49:20 +0100 Subject: [PATCH] New senor values: - Tank Level in percentage - Oil change maintenace - AdBlue Range - Parking Light - CarType - Primary + secondary engine range in percentage + Fixed negative maintenance values --- .../audiconnect/audi_connect_account.py | 78 +++++++++++++++++-- custom_components/audiconnect/audi_models.py | 50 +++++++----- .../audiconnect/audi_services.py | 4 +- custom_components/audiconnect/const.py | 1 + custom_components/audiconnect/dashboard.py | 20 +++++ custom_components/audiconnect/manifest.json | 2 + hacs.json | 1 - 7 files changed, 127 insertions(+), 29 deletions(-) diff --git a/custom_components/audiconnect/audi_connect_account.py b/custom_components/audiconnect/audi_connect_account.py index 948ac0ad..62dbeb16 100644 --- a/custom_components/audiconnect/audi_connect_account.py +++ b/custom_components/audiconnect/audi_connect_account.py @@ -740,7 +740,7 @@ def last_update_time_supported(self): def service_inspection_time(self): """Return time left for service inspection""" if self.service_inspection_time_supported: - return -int( + return int( self._vehicle.fields.get("MAINTENANCE_INTERVAL_TIME_TO_INSPECTION") ) @@ -754,7 +754,7 @@ def service_inspection_time_supported(self): def service_inspection_distance(self): """Return distance left for service inspection""" if self.service_inspection_distance_supported: - return -int( + return int( self._vehicle.fields.get("MAINTENANCE_INTERVAL_DISTANCE_TO_INSPECTION") ) @@ -764,11 +764,25 @@ def service_inspection_distance_supported(self): if check and parse_int(check): return True + @property + def service_adblue_distance(self): + """Return distance left for service inspection""" + if self.service_adblue_distance_supported: + return int( + self._vehicle.fields.get("ADBLUE_RANGE") + ) + + @property + def service_adblue_distance_supported(self): + check = self._vehicle.fields.get("ADBLUE_RANGE") + if check and parse_int(check): + return True + @property def oil_change_time(self): """Return time left for oil change""" if self.oil_change_time_supported: - return -int( + return int( self._vehicle.fields.get("MAINTENANCE_INTERVAL_TIME_TO_OIL_CHANGE") ) @@ -782,7 +796,7 @@ def oil_change_time_supported(self): def oil_change_distance(self): """Return distance left for oil change""" if self.oil_change_distance_supported: - return -int( + return int( self._vehicle.fields.get("MAINTENANCE_INTERVAL_DISTANCE_TO_OIL_CHANGE") ) @@ -796,12 +810,19 @@ def oil_change_distance_supported(self): def oil_level(self): """Return oil level percentage""" if self.oil_level_supported: - return float(self._vehicle.fields.get("OIL_LEVEL_DIPSTICKS_PERCENTAGE")) + val = self._vehicle.fields.get("OIL_LEVEL_DIPSTICKS_PERCENTAGE") + if type(val) is bool: + if val: + return 100 + else: + return 1 + if parse_float(val): + return True @property def oil_level_supported(self): check = self._vehicle.fields.get("OIL_LEVEL_DIPSTICKS_PERCENTAGE") - if check and parse_float(check): + if check is not None: return True @property @@ -850,8 +871,11 @@ def preheater_remaining(self): def parking_light(self): """Return true if parking light is on""" if self.parking_light_supported: - check = self._vehicle.fields.get("LIGHT_STATUS") - return check != "2" + try: + check = self._vehicle.fields.get("LIGHT_STATUS") + return check[0]["status"] != "off" or check[1]["status"] != "off" + except: + return False @property def parking_light_supported(self): @@ -1248,6 +1272,18 @@ def primary_engine_range_supported(self): if check and check != "unsupported": return True + @property + def primary_engine_range_percent(self): + """Return primary engine range""" + if self.primary_engine_range_percent_supported: + return self._vehicle.state.get("primaryEngineRangePercent") + + @property + def primary_engine_range_percent_supported(self): + check = self._vehicle.state.get("primaryEngineRangePercent") + if check and check != "unsupported": + return True + @property def secondary_engine_range(self): """Return secondary engine range""" @@ -1260,6 +1296,32 @@ def secondary_engine_range_supported(self): if check and check != "unsupported": return True + @property + def car_type(self): + """Return secondary engine range""" + if self.car_type_supported: + return self._vehicle.state.get("carType") + + @property + def car_type_supported(self): + check = self._vehicle.state.get("carType") + if check and check != "unsupported": + return True + + @property + def secondary_engine_range_percent(self): + """Return secondary engine range""" + if self.secondary_engine_range_percent_supported: + return self._vehicle.state.get("secondaryEngineRangePercent") + + @property + def secondary_engine_range_percent_supported(self): + check = self._vehicle.state.get("secondaryEngineRangePercent") + if check and check != "unsupported": + return True + + + @property def hybrid_range(self): """Return hybrid range""" diff --git a/custom_components/audiconnect/audi_models.py b/custom_components/audiconnect/audi_models.py index fa7da90f..3b21075c 100644 --- a/custom_components/audiconnect/audi_models.py +++ b/custom_components/audiconnect/audi_models.py @@ -40,30 +40,44 @@ def __init__(self, data): self.data_fields = [] self.states = [] - self._tryAppendFieldWithTs(data, "TOTAL_RANGE", ["fuelStatus", "rangeStatus", "value", "totalRange_km"]) - self._tryAppendFieldWithTs(data, "UTC_TIME_AND_KILOMETER_STATUS", ["measurements", "odometerStatus", "value", "odometer"]) - self._tryAppendFieldWithTs(data, "MAINTENANCE_INTERVAL_TIME_TO_INSPECTION", ["vehicleHealthInspection", "maintenanceStatus", "value", "inspectionDue_days"]) - self._tryAppendFieldWithTs(data, "MAINTENANCE_INTERVAL_DISTANCE_TO_INSPECTION", ["vehicleHealthInspection", "maintenanceStatus", "value", "inspectionDue_km"]) + self._tryAppendFieldWithTs(data, "TOTAL_RANGE", ["fuelStatus", "rangeStatus", "value", "totalRange_km"]) + self._tryAppendFieldWithTs(data, "TANK_LEVEL_IN_PERCENTAGE", ["measurements", "fuelLevelStatus", "value", "currentFuelLevel_pct"]) + self._tryAppendFieldWithTs(data, "UTC_TIME_AND_KILOMETER_STATUS", ["measurements", "odometerStatus", "value", "odometer"]) + self._tryAppendFieldWithTs(data, "MAINTENANCE_INTERVAL_TIME_TO_INSPECTION", ["vehicleHealthInspection", "maintenanceStatus", "value", "inspectionDue_days"]) + self._tryAppendFieldWithTs(data, "MAINTENANCE_INTERVAL_DISTANCE_TO_INSPECTION", ["vehicleHealthInspection", "maintenanceStatus", "value", "inspectionDue_km"]) + + self._tryAppendFieldWithTs(data, "MAINTENANCE_INTERVAL_TIME_TO_OIL_CHANGE", ["vehicleHealthInspection", "maintenanceStatus", "value", "oilServiceDue_days"]) + self._tryAppendFieldWithTs(data, "MAINTENANCE_INTERVAL_DISTANCE_TO_OIL_CHANGE", ["vehicleHealthInspection", "maintenanceStatus", "value", "oilServiceDue_km"]) + + self._tryAppendFieldWithTs(data, "OIL_LEVEL_DIPSTICKS_PERCENTAGE", ["oilLevel", "oilLevelStatus", "value", "value"]) + self._tryAppendFieldWithTs(data, "ADBLUE_RANGE", ["measurements", "rangeStatus", "value", "adBlueRange"]) + + self._tryAppendFieldWithTs(data, "LIGHT_STATUS", ["vehicleLights", "lightsStatus", "value", "lights"]) + self.appendWindowState(data) self.appendSunRoofState(data) self.appendDoorState(data) self.appendHoodState(data) + + self._tryAppendStateWithTs(data, "carType", -1, ["fuelStatus", "rangeStatus", "value", "carType"]) - self._tryAppendStateWithTs(data, "engineTypeFirstEngine", -2, ["fuelStatus", "rangeStatus", "value", "primaryEngine", "type"]) - self._tryAppendStateWithTs(data, "primaryEngineRange", -2, ["fuelStatus", "rangeStatus", "value", "primaryEngine", "remainingRange_km"]) - self._tryAppendStateWithTs(data, "engineTypeSecondEngine", -2, ["fuelStatus", "rangeStatus", "value", "secondaryEngine", "type"]) - self._tryAppendStateWithTs(data, "secondaryEngineRange", -2, ["fuelStatus", "rangeStatus", "value", "secondaryEngine", "remainingRange_km"]) - self._tryAppendStateWithTs(data, "hybridRange", -1, ["fuelStatus", "rangeStatus", "value", "totalRange_km"]) - - self._tryAppendStateWithTs(data, "stateOfCharge", -1, ["charging", "batteryStatus", "value", "currentSOC_pct"]) - self._tryAppendStateWithTs(data, "chargingMode", -1, ["charging", "chargingStatus", "value", "chargeType"]) - self._tryAppendStateWithTs(data, "actualChargeRate", -1, ["charging", "chargingStatus", "value", "chargeRate_kmph"]) - self._tryAppendStateWithTs(data, "chargingPower", -1, ["charging", "chargingStatus", "value", "chargePower_kW"]) - self._tryAppendStateWithTs(data, "chargeMode", -1, ["charging", "chargingStatus", "value", "chargeMode"]) - self._tryAppendStateWithTs(data, "chargingState", -1, ["charging", "chargingStatus", "value", "chargingState"]) - self._tryAppendStateWithTs(data, "plugState", -1, ["charging", "plugStatus", "value", "plugConnectionState"]) - self._tryAppendStateWithTs(data, "remainingChargingTime", -1, ["charging", "plugStatus", "value", "remainingChargingTimeToComplete_min"]) + self._tryAppendStateWithTs(data, "engineTypeFirstEngine", -2, ["fuelStatus", "rangeStatus", "value", "primaryEngine", "type"]) + self._tryAppendStateWithTs(data, "primaryEngineRange", -2, ["fuelStatus", "rangeStatus", "value", "primaryEngine", "remainingRange_km"]) + self._tryAppendStateWithTs(data, "primaryEngineRangePercent", -2, ["fuelStatus", "rangeStatus", "value", "primaryEngine", "currentSOC_pct"]) + self._tryAppendStateWithTs(data, "engineTypeSecondEngine", -2, ["fuelStatus", "rangeStatus", "value", "secondaryEngine", "type"]) + self._tryAppendStateWithTs(data, "secondaryEngineRange", -2, ["fuelStatus", "rangeStatus", "value", "secondaryEngine", "remainingRange_km"]) + self._tryAppendStateWithTs(data, "secondaryEngineRangePercent", -2, ["fuelStatus", "rangeStatus", "value", "secondaryEngine", "currentSOC_pct"]) + self._tryAppendStateWithTs(data, "hybridRange", -1, ["fuelStatus", "rangeStatus", "value", "totalRange_km"]) + + self._tryAppendStateWithTs(data, "stateOfCharge", -1, ["charging", "batteryStatus", "value", "currentSOC_pct"]) + self._tryAppendStateWithTs(data, "chargingMode", -1, ["charging", "chargingStatus", "value", "chargeType"]) + self._tryAppendStateWithTs(data, "actualChargeRate", -1, ["charging", "chargingStatus", "value", "chargeRate_kmph"]) + self._tryAppendStateWithTs(data, "chargingPower", -1, ["charging", "chargingStatus", "value", "chargePower_kW"]) + self._tryAppendStateWithTs(data, "chargeMode", -1, ["charging", "chargingStatus", "value", "chargeMode"]) + self._tryAppendStateWithTs(data, "chargingState", -1, ["charging", "chargingStatus", "value", "chargingState"]) + self._tryAppendStateWithTs(data, "plugState", -1, ["charging", "plugStatus", "value", "plugConnectionState"]) + self._tryAppendStateWithTs(data, "remainingChargingTime", -1, ["charging", "plugStatus", "value", "remainingChargingTimeToComplete_min"]) def _tryAppendStateWithTs(self, json, name, tsoff, loc): diff --git a/custom_components/audiconnect/audi_services.py b/custom_components/audiconnect/audi_services.py index 8b461eb4..120db807 100644 --- a/custom_components/audiconnect/audi_services.py +++ b/custom_components/audiconnect/audi_services.py @@ -880,9 +880,9 @@ async def login_request(self, user: str, password: str): # form_data with password # 2022-01-29: new HTML response uses a js two build the html form data + button. - # Therefore it's not possible to extract hmac and other form data. + # Therefore it's not possible to extract hmac and other form data. # --> extract hmac from embedded js snippet. - regex_res = re.findall('"hmac"\s*:\s*"[0-9a-fA-F]+"', email_rsptxt) + regex_res = re.findall('"hmac"\\s*:\\s*"[0-9a-fA-F]+"', email_rsptxt) if regex_res: submit_url = submit_url.replace("identifier", "authenticate") submit_data["hmac"] = regex_res[0].split(":")[1].strip('"') diff --git a/custom_components/audiconnect/const.py b/custom_components/audiconnect/const.py index f5fa2e04..26519db0 100644 --- a/custom_components/audiconnect/const.py +++ b/custom_components/audiconnect/const.py @@ -26,6 +26,7 @@ "range", "service_inspection_time", "service_inspection_distance", + "service_adblue_distance", "oil_change_time", "oil_change_distance", "oil_level", diff --git a/custom_components/audiconnect/dashboard.py b/custom_components/audiconnect/dashboard.py index a8e47985..dd4fa0e5 100644 --- a/custom_components/audiconnect/dashboard.py +++ b/custom_components/audiconnect/dashboard.py @@ -386,7 +386,9 @@ def create_instruments(): Lock(), Preheater(), Sensor(attr="model", name="Model", icon="mdi:car-info", unit=None), + Sensor(attr="service_adblue_distance", name="AdBlue Range", icon="mdi:gas-station", unit="km"), Sensor(attr="mileage", name="Mileage", icon="mdi:speedometer", unit="km"), + Sensor(attr="service_adblue_distance", name="AdBlue range", icon="mdi:gas-station", unit="km"), Sensor(attr="range", name="Range", icon="mdi:gas-station", unit="km"), Sensor( attr="service_inspection_time", @@ -452,6 +454,24 @@ def create_instruments(): icon="mdi:gas-station-outline", unit="km", ), + Sensor( + attr="primary_engine_range_percent", + name="Primary engine Percent", + icon="mdi:gas-station-outline", + unit="%", + ), + Sensor( + attr="car_type", + name="Car Type", + icon="mdi:car-info", + unit=None, + ), + Sensor( + attr="secondary_engine_range_percent", + name="Secondary engine Percent", + icon="mdi:gas-station-outline", + unit="%", + ), Sensor( attr="charging_power", name="Charging power", icon="mdi:flash", unit="kW" ), diff --git a/custom_components/audiconnect/manifest.json b/custom_components/audiconnect/manifest.json index 990406a3..04dd9102 100644 --- a/custom_components/audiconnect/manifest.json +++ b/custom_components/audiconnect/manifest.json @@ -3,6 +3,8 @@ "name": "Audi Connect", "config_flow": true, "documentation": "https://github.com/arjenvrh/audi_connect_ha", + "integration_type": "hub", + "iot_class": "cloud_polling", "issue_tracker": "https://github.com/arjenvrh/audi_connect_ha/issues", "requirements": ["beautifulsoup4"], "dependencies": [], diff --git a/hacs.json b/hacs.json index 85105dab..09ee7538 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,4 @@ { "name": "Audi connect", - "domains": ["sensor", "binary_sensor", "switch", "device_tracker", "lock"], "homeassistant": "0.110.0" }