Skip to content

Commit

Permalink
Merge pull request #389 from itchannel/1.59
Browse files Browse the repository at this point in the history
1.59
  • Loading branch information
itchannel committed Oct 22, 2023
2 parents c1c3173 + 6220100 commit 399fc2e
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 456 deletions.
91 changes: 75 additions & 16 deletions custom_components/fordpass/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
}
)

VIN_SCHEME = vol.Schema(
{
vol.Required(VIN): str,
}
)

@callback
def configured_vehicles(hass):
Expand All @@ -50,24 +55,50 @@ async def validate_input(hass: core.HomeAssistant, data):
Data has the keys from DATA_SCHEMA with values provided by the user.
"""
_LOGGER.debug(data[REGION])
config_path = hass.config.path("custom_components/fordpass/" + data[CONF_USERNAME] + "_fordpass_token.txt")
vehicle = Vehicle(data[CONF_USERNAME], data[CONF_PASSWORD], "", data[REGION], 1, config_path)
configPath = hass.config.path("custom_components/fordpass/" + data[CONF_USERNAME] + "_fordpass_token.txt")
vehicle = Vehicle(data[CONF_USERNAME], data[CONF_PASSWORD], "", data[REGION], 1, configPath)

try:
result = await hass.async_add_executor_job(vehicle.auth)
except Exception as ex:
raise InvalidAuth from ex

if result:
vehicles = await(hass.async_add_executor_job(vehicle.vehicles))

try:
if result:
vehicles = await(hass.async_add_executor_job(vehicle.vehicles))
except Exception as ex:
vehicles = None
#except Exception as ex:
# raise InvalidAuth from ex

#result3 = await hass.async_add_executor_job(vehicle.vehicles)
# Disabled due to API change
#vinfound = False
#for car in result3:
# if car["vin"] == data[VIN]:
# vinfound = True
#if vinfound == False:
# _LOGGER.debug("Vin not found in account, Is your VIN valid?")
if not result:
_LOGGER.error("Failed to authenticate with fordpass")
raise CannotConnect

# Return info that you want to store in the config entry.
return vehicles

#return {"title": f"Vehicle ({data[VIN]})"}

async def validate_vin(hass: core.HomeAssistant, data):
configPath = hass.config.path("custom_components/fordpass/" + data[CONF_USERNAME] + "_fordpass_token.txt")

vehicle = Vehicle(data[CONF_USERNAME], data[CONF_PASSWORD], data[VIN], data[REGION], 1, configPath)
test = await(hass.async_add_executor_job(vehicle.get_status))
_LOGGER.debug("GOT SOMETHING BACK?")
_LOGGER.debug(test)
if test and test.status_code == 200:
_LOGGER.debug("200 Code")
return True
if not test:
raise InvalidVin
return False

class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for FordPass."""
Expand All @@ -82,9 +113,15 @@ async def async_step_user(self, user_input=None):
try:
info = await validate_input(self.hass, user_input)
self.login_input = user_input
self.vehicles = info["userVehicles"]["vehicleDetails"]
if info is None:
self.vehicles = None
_LOGGER.debug("NO VEHICLES FOUND")
else:
self.vehicles = info["userVehicles"]["vehicleDetails"]
if self.vehicles is None:
return await self.async_step_vin()
return await self.async_step_vehicle()
# return self.async_create_entry(title=info["title"], data=user_input)
#return self.async_create_entry(title=info["title"], data=user_input)
except CannotConnect:
print("EXCEPT")
errors["base"] = "cannot_connect"
Expand All @@ -99,15 +136,37 @@ async def async_step_user(self, user_input=None):
return self.async_show_form(
step_id="user", data_schema=DATA_SCHEMA, errors=errors
)

async def async_step_vin(self, user_input=None):
"""Handle manual VIN entry"""
errors = {}
if user_input is not None:
_LOGGER.debug(self.login_input)
_LOGGER.debug(user_input)
data = self.login_input
data["vin"] = user_input["vin"]
vehicle = None
try:
vehicle = await validate_vin(self.hass, data)
except InvalidVin:
errors["base"] = "invalid_vin"
except Exception:
errors["base"] = "unknown"

if vehicle :
return self.async_create_entry(title=f"Vehicle ({user_input[VIN]})", data=self.login_input)

# return self.async_create_entry(title=f"Enter VIN", data=self.login_input)
_LOGGER.debug(self.login_input)
return self.async_show_form(step_id="vin", data_schema=VIN_SCHEME, errors=errors)

async def async_step_vehicle(self, user_input=None):
"""Show user vehicle selection form"""
if user_input is not None:
_LOGGER.debug("Checking Vehicle is accessible")
self.login_input[VIN] = user_input["vin"]
_LOGGER.debug(self.login_input)
return self.async_create_entry(title=f"Vehicle ({user_input[VIN]})", data=self.login_input)

_LOGGER.debug(self.vehicles)

configured = configured_vehicles(self.hass)
Expand All @@ -126,10 +185,10 @@ async def async_step_vehicle(self, user_input=None):
return self.async_abort(reason="no_vehicles")
return self.async_show_form(
step_id="vehicle",
data_schema=vol.Schema(
{vol.Required(VIN): vol.In(avaliable_vehicles)}
data_schema = vol.Schema(
{ vol.Required(VIN): vol.In(avaliable_vehicles)}
),
errors={}
errors = {}
)

@staticmethod
Expand All @@ -145,7 +204,6 @@ def __init__(self, config_entry: config_entries.ConfigEntry):
self.config_entry = config_entry

async def async_step_init(self, user_input=None):
"""Options Flow steps"""
if user_input is not None:
return self.async_create_entry(title="", data=user_input)
options = {
Expand All @@ -163,7 +221,7 @@ async def async_step_init(self, user_input=None):
): vol.In(DISTANCE_UNITS),
vol.Optional(
DISTANCE_CONVERSION_DISABLED,
default=self.config_entry.options.get(
default = self.config_entry.options.get(
DISTANCE_CONVERSION_DISABLED, DISTANCE_CONVERSION_DISABLED_DEFAULT
),
): bool,
Expand All @@ -173,6 +231,7 @@ async def async_step_init(self, user_input=None):
UPDATE_INTERVAL, UPDATE_INTERVAL_DEFAULT
),
): int,

}

return self.async_show_form(step_id="init", data_schema=vol.Schema(options))
Expand Down
42 changes: 21 additions & 21 deletions custom_components/fordpass/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,24 @@
REGION_OPTIONS = ["UK&Europe", "Australia", "North America & Canada"]

SENSORS = {
"odometer": {"icon": "mdi:counter", "state_class": "total", "device_class": "distance"},
"fuel": {"icon": "mdi:gas-station"},
"battery": {"icon": "mdi:car-battery"},
"oil": {"icon": "mdi:oil"},
"tirePressure": {"icon": "mdi:car-tire-alert"},
"odometer": {"icon": "mdi:counter", "state_class": "total", "device_class": "distance", "api_key": "odometer", "measurement": "km"},
"fuel": {"icon": "mdi:gas-station", "api_key": ["fuelLevel", "xevBatteryStateOfCharge"], "measurement": "%"},
"battery": {"icon": "mdi:car-battery", "device_class": "battery","state_class": "measurement", "api_key": "batteryStateOfCharge", "measurement": "%"},
"oil": {"icon": "mdi:oil", "api_key": "oilLifeRemaining", "measurement": "%"},
"tirePressure": {"icon": "mdi:car-tire-alert", "api_key": "tirePressure"},
# "gps": {"icon": "mdi:radar"},
"alarm": {"icon": "mdi:bell"},
"ignitionStatus": {"icon": "hass:power"},
"doorStatus": {"icon": "mdi:car-door"},
"windowPosition": {"icon": "mdi:car-door"},
"lastRefresh": {"icon": "mdi:clock", "device_class": "timestamp"},
"elVeh": {"icon": "mdi:ev-station"},
"elVehCharging": {"icon": "mdi:ev-station"},
"speed": {"icon": "mdi:speedometer"},
"indicators": {"icon": "mdi:engine-outline"},
"coolantTemp": {"icon": "mdi:coolant-temperature", "state_class": "measurement", "device_class": "temperature"},
"outsideTemp": {"icon": "mdi:thermometer", "state_class": "measurement", "device_class": "temperature"},
"engineOilTemp": {"icon": "mdi:oil-temperature", "state_class": "measurement", "device_class": "temperature"},
"alarm": {"icon": "mdi:bell", "api_key": "alarmStatus"},
"ignitionStatus": {"icon": "hass:power", "api_key": "ignitionStatus"},
"doorStatus": {"icon": "mdi:car-door", "api_key": "doorStatus"},
"windowPosition": {"icon": "mdi:car-door", "api_key": "windowStatus"},
"lastRefresh": {"icon": "mdi:clock", "device_class": "timestamp", "api_key": "lastRefresh"},
"elVeh": {"icon": "mdi:ev-station", "api_key": "xevBatteryRange", "device_class": "distance", "state_class": "measurement", "measurement": "km"},
"elVehCharging": {"icon": "mdi:ev-station", "api_key": "xevBatteryChargeDisplayStatus"},
"speed": {"icon": "mdi:speedometer", "device_class": "speed", "state_class": "measurement", "api_key": "speed", "measurement": "km/h"},
"indicators": {"icon": "mdi:engine-outline", "api_key": "indicators"},
"coolantTemp": {"icon": "mdi:coolant-temperature", "api_key": "engineCoolantTemp" ,"state_class": "measurement", "device_class": "temperature", "measurement": "°C"},
"outsideTemp": {"icon": "mdi:thermometer", "state_class": "measurement", "device_class": "temperature", "api_key": "outsideTemperature", "measurement": "°C"},
"engineOilTemp": {"icon": "mdi:oil-temperature", "state_class": "measurement", "device_class": "temperature", "api_key": "engineOilTemp", "measurement": "°C"},
# "deepSleepInProgress": {
# "icon": "mdi:power-sleep",
# "name": "Deep Sleep Mode Active",
Expand All @@ -56,11 +56,11 @@
# "icon": "mdi:one-up",
# "name": "Firmware Update In Progress",
# },
"remoteStartStatus": {"icon": "mdi:remote"},
"remoteStartStatus": {"icon": "mdi:remote", "api_key": "remoteStartCountdownTimer"},
# "zoneLighting": {"icon": "mdi:spotlight-beam"},
"messages": {"icon": "mdi:message-text"},
"dieselSystemStatus": {"icon": "mdi:smoking-pipe"},
"exhaustFluidLevel": {"icon": "mdi:barrel"}
"messages": {"icon": "mdi:message-text", "api_key": "messages", "measurement": "messages"},
"dieselSystemStatus": {"icon": "mdi:smoking-pipe", "api_key": "dieselExhaustFilterStatus"},
"exhaustFluidLevel": {"icon": "mdi:barrel", "api_key": "dieselExhaustFluidLevel", "measurement": "%"},
}

SWITCHES = {"ignition": {"icon": "hass:power"}, "guardmode": {"icon": "mdi:shield-key"}}
Expand Down
16 changes: 10 additions & 6 deletions custom_components/fordpass/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass, config_entry, async_add_entities):
"""Add the lock from the config."""
entry = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]

lock = Lock(entry)
if lock.coordinator.data["metrics"]["doorLockStatus"] and lock.coordinator.data["metrics"]["doorLockStatus"][0]["value"] != "ERROR":

door_lock_status = lock.coordinator.data.get("metrics", {}).get("doorLockStatus", [])
all_doors_status = next((item for item in door_lock_status if item.get("vehicleDoor") == "ALL_DOORS"), None)

if all_doors_status and all_doors_status.get("value") != "ERROR":
async_add_entities([lock], False)
else:
_LOGGER.debug("Ford model doesn't support remote locking")


class Lock(FordPassEntity, LockEntity):
"""Defines the vehicle's lock."""
def __init__(self, coordinator):
"""Initialize."""
self._device_id = "fordpass_doorlock"
self.coordinator = coordinator
self.data = coordinator.data["metrics"]
self.data = coordinator.data.get("metrics", {})

# Required for HA 2022.7
self.coordinator_context = object()
Expand Down Expand Up @@ -61,9 +63,11 @@ async def async_unlock(self, **kwargs):
@property
def is_locked(self):
"""Determine if the lock is locked."""
if self.coordinator.data["metrics"] is None or self.coordinator.data["metrics"]["doorLockStatus"] is None:
door_lock_status = self.coordinator.data.get("metrics", {}).get("doorLockStatus", [])
all_doors_status = next((item for item in door_lock_status if item.get("vehicleDoor") == "ALL_DOORS"), None)
if not all_doors_status:
return None
return self.coordinator.data["metrics"]["doorLockStatus"][0]["value"] == "LOCKED"
return all_doors_status.get("value") == "LOCKED" or all_doors_status.get("value") == "DOUBLE_LOCKED"

@property
def icon(self):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/fordpass/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"loggers": ["custom_components.fordpass"],
"requirements": [],
"ssdp": [],
"version": "0.1.58",
"version": "0.1.59",
"zeroconf": []
}
Loading

0 comments on commit 399fc2e

Please sign in to comment.