diff --git a/LICENSE.md b/LICENSE.md index f49a4e1..18f373e 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,201 +1,21 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file +MIT License + +Copyright (c) 2024 Daniel Raper + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 327ebf3..77afff1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # NissanConnect for Home Assistant -An unofficial integration for interacting with NissanConnect vehicles in Europe. Based on the work of [mitchellrj](https://github.com/mitchellrj) and [tobiaswk](https://github.com/Tobiaswk/dartnissanconnect). I have no affiliation with Nissan besides owning one of their cars. +An unofficial integration for interacting with NissanConnect vehicles in Europe. Based on the work of [mitchellrj](https://github.com/mitchellrj/kamereon-python) and [tobiaswk](https://github.com/Tobiaswk/dartnissanconnect). I have no affiliation with Nissan besides owning one of their cars. _Please note this integration is only for vehicles using the NissanConnect app, not NissanConnect EV or any other app._ diff --git a/custom_components/nissan_connect/climate.py b/custom_components/nissan_connect/climate.py index 02e700c..1b26243 100644 --- a/custom_components/nissan_connect/climate.py +++ b/custom_components/nissan_connect/climate.py @@ -12,7 +12,7 @@ SUPPORT_HVAC = [HVACMode.HEAT_COOL, HVACMode.OFF] from .base import KamereonEntity -from .kamereon import Feature, HVACAction, HVACStatus +from .kamereon import Feature, HVACAction from .const import DOMAIN, DATA_VEHICLES, DATA_COORDINATOR_FETCH, DATA_COORDINATOR_POLL _LOGGER = logging.getLogger(__name__) @@ -46,9 +46,7 @@ def __init__(self, coordinator, vehicle, hass): @property def hvac_mode(self): - if self.vehicle.hvac_status is None: - return HVACMode.OFF - elif self.vehicle.hvac_status is HVACStatus.ON: + if self.vehicle.hvac_status: return HVACMode.HEAT_COOL return HVACMode.OFF @@ -67,7 +65,7 @@ def target_temperature(self): @property def hvac_action(self): """Shows heating or cooling depending on temperature.""" - if self.vehicle.hvac_status is not None and self.vehicle.hvac_status is HVACStatus.ON: + if self.vehicle.hvac_status: if self._target < self.vehicle.internal_temperature: return HASSHVACAction.COOLING else: @@ -83,7 +81,7 @@ def set_temperature(self, **kwargs): if not temperature: return - if self.vehicle.hvac_status == HVACStatus.ON: + if self.vehicle.hvac_status: self._target = temperature self.vehicle.set_hvac_status(HVACAction.START, temperature) else: @@ -96,10 +94,10 @@ async def async_set_hvac_mode(self, hvac_mode): if hvac_mode == HVACMode.OFF: await self._hass.async_add_executor_job(self.vehicle.set_hvac_status, HVACAction.STOP) - self._hass.async_create_task(self._async_fetch_loop(HVACStatus.OFF)) + self._hass.async_create_task(self._async_fetch_loop(False)) elif hvac_mode == HVACMode.HEAT_COOL: await self._hass.async_add_executor_job(self.vehicle.set_hvac_status, HVACAction.START, int(self._target)) - self._hass.async_create_task(self._async_fetch_loop(HVACStatus.ON)) + self._hass.async_create_task(self._async_fetch_loop(True)) async def async_turn_off(self) -> None: await self.async_set_hvac_mode(HVACMode.OFF) diff --git a/custom_components/nissan_connect/coordinator.py b/custom_components/nissan_connect/coordinator.py index 2afc36e..0e34fe4 100644 --- a/custom_components/nissan_connect/coordinator.py +++ b/custom_components/nissan_connect/coordinator.py @@ -3,7 +3,7 @@ from datetime import timedelta from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN, DATA_VEHICLES, DEFAULT_INTERVAL_POLL, DEFAULT_INTERVAL_CHARGING, DEFAULT_INTERVAL_STATISTICS, DEFAULT_INTERVAL_FETCH, DATA_COORDINATOR_FETCH, DATA_COORDINATOR_POLL -from .kamereon import Feature, PluggedStatus, ChargingStatus, HVACStatus, Period +from .kamereon import Feature, PluggedStatus, ChargingStatus, Period _LOGGER = logging.getLogger(__name__) @@ -49,7 +49,7 @@ def __init__(self, hass, config): self._hass = hass self._vehicles = hass.data[DOMAIN][DATA_VEHICLES] self._config = config - self._pluggednotcharging = 0 + self._pluggednotcharging = {key: 0 for key in self._vehicles} def set_next_interval(self): """Calculate the next update interval.""" @@ -62,16 +62,16 @@ def set_next_interval(self): if Feature.BATTERY_STATUS in self._vehicles[vehicle].features and self._vehicles[vehicle].plugged_in == PluggedStatus.PLUGGED: # If we are plugged in but not charging, increment a counter if self._vehicles[vehicle].charging != ChargingStatus.CHARGING: - self._pluggednotcharging += 1 + self._pluggednotcharging[vehicle] += 1 else: # If we are plugged in and charging, reset counter - self._pluggednotcharging = 0 + self._pluggednotcharging[vehicle] = 0 # If we haven't hit the counter limit, use the shorter interval - if self._pluggednotcharging < 5: + if self._pluggednotcharging[vehicle] < 5: interval = interval_charging if interval_charging < interval else interval # Update every minute if HVAC on - if self._vehicles[vehicle].hvac_status == HVACStatus.ON: + if self._vehicles[vehicle].hvac_status: interval = 1 if interval != (self.update_interval.seconds / 60): diff --git a/custom_components/nissan_connect/kamereon/__init__.py b/custom_components/nissan_connect/kamereon/__init__.py new file mode 100644 index 0000000..9202cf5 --- /dev/null +++ b/custom_components/nissan_connect/kamereon/__init__.py @@ -0,0 +1 @@ +from .kamereon import * diff --git a/custom_components/nissan_connect/kamereon.py b/custom_components/nissan_connect/kamereon/kamereon.py similarity index 63% rename from custom_components/nissan_connect/kamereon.py rename to custom_components/nissan_connect/kamereon/kamereon.py index 3acf048..8b31b09 100644 --- a/custom_components/nissan_connect/kamereon.py +++ b/custom_components/nissan_connect/kamereon/kamereon.py @@ -1,61 +1,20 @@ -# Copyright 2020 Richard Mitchell - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Based on work by @mitchellrj and @Tobiaswk +# Portions re-licensed from Apache License, Version 2.0 with permission import collections import datetime -import enum import json import os -import requests import logging from typing import List +import requests from oauthlib.common import generate_nonce from oauthlib.oauth2 import TokenExpiredError from requests_oauthlib import OAuth2Session +from .kamereon_const import * _LOGGER = logging.getLogger(__name__) -API_VERSION = 'protocol=1.0,resource=2.1' -SRP_KEY = 'D5AF0E14718E662D12DBB4FE42304DF5A8E48359E22261138B40AA16CC85C76A11B43200A1EECB3C9546A262D1FBD51ACE6FCDE558C00665BBF93FF86B9F8F76AA7A53CA74F5B4DFF9A4B847295E7D82450A2078B5A28814A7A07F8BBDD34F8EEB42B0E70499087A242AA2C5BA9513C8F9D35A81B33A121EEF0A71F3F9071CCD' - - -settings_map = { - 'nissan': { - 'EU': { - 'client_id': 'a-ncb-nc-android-prod', - 'client_secret': '6GKIax7fGT5yPHuNmWNVOc4q5POBw1WRSW39ubRA8WPBmQ7MOxhm75EsmKMKENem', - 'scope': 'openid profile vehicles', - 'auth_base_url': 'https://prod.eu2.auth.kamereon.org/kauth/', - 'realm': 'a-ncb-prod', - 'redirect_uri': 'org.kamereon.service.nci:/oauth2redirect', - 'car_adapter_base_url': 'https://alliance-platform-caradapter-prod.apps.eu2.kamereon.io/car-adapter/', - 'notifications_base_url': 'https://alliance-platform-notifications-prod.apps.eu2.kamereon.io/notifications/', - 'user_adapter_base_url': 'https://alliance-platform-usersadapter-prod.apps.eu2.kamereon.io/user-adapter/', - 'user_base_url': 'https://nci-bff-web-prod.apps.eu2.kamereon.io/bff-web/' - } - }, - 'mitsubishi': {}, - 'renault': {}, -} - - -USERS = 'users' -VEHICLES = 'vehicles' -CATEGORIES = 'categories' -NOTIFICATION_RULES = 'notification_rules' -NOTIFICATION_TYPES = 'notification_types' -NOTIFICATION_CATEGORIES = 'notification_categories' _registry = { USERS: {}, VEHICLES: {}, @@ -65,489 +24,9 @@ NOTIFICATION_CATEGORIES: {}, } - -class HVACAction(enum.Enum): - # Start or schedule start - START = 'start' - # Stop active HVAC - STOP = 'stop' - # Cancel scheduled HVAC - CANCEL = 'cancel' - - -class HVACStatus(enum.Enum): - OFF = 'off' - ON = 'on' - - -class LockStatus(enum.Enum): - CLOSED = 'closed' - LOCKED = 'locked' - OPEN = 'open' - UNLOCKED = 'unlocked' - - -class Door(enum.Enum): - HATCH = 'hatch' - FRONT_LEFT = 'front_left' - FRONT_RIGHT = 'front_right' - REAR_LEFT = 'rear_left' - REAR_RIGHT = 'rear_right' - - -class LockableDoorGroup(enum.Enum): - DOORS_AND_HATCH = 'doors_hatch' - DRIVERS_DOOR = 'driver_s_door' - HATCH = 'hatch' - - -class ChargingSpeed(enum.Enum): - NONE = None - SLOW = 1 - NORMAL = 2 - FAST = 3 - FASTEST = 4 - - -class ChargingStatus(enum.Enum): - ERROR = -1 - NOT_CHARGING = 0 - CHARGING = 1 - - -class PluggedStatus(enum.Enum): - ERROR = -1 - NOT_PLUGGED = 0 - PLUGGED = 1 - - -class Period(enum.Enum): - DAILY = 0 - MONTHLY = 1 - YEARLY = 2 - - -class Feature(enum.Enum): - BREAKDOWN_ASSISTANCE_CALL = '1' - SVT_WITH_VEHICLE_BLOCKAGE = '10' - MAINTENANCE_ALERT = '101' - VEHICLE_SOFTWARE_UPDATES = '107' - MY_CAR_FINDER = '12' - MIL_ON_NOTIFICATION = '15' - VEHICLE_HEALTH_REPORT = '18' - ADVANCED_CAN = '201' - VEHICLE_STATUS_CHECK = '202' - LOCK_STATUS_CHECK = '2021' - NAVIGATION_FACTORY_RESET = '208' - MESSAGES_TO_THE_VEHICLE = '21' - VEHICLE_DATA = '2121' - VEHICLE_DATA_2 = '2122' - VEHICLE_WIFI = '213' - ADVANCED_VEHICLE_DIAGNOSTICS = '215' - NAVIGATION_MAP_UPDATES = '217' - VEHICLE_SETTINGS_TRANSFER = '221' - LAST_MILE_NAVIGATION = '227' - GOOGLE_STREET_VIEW = '229' - GOOGLE_SATELITE_VIEW = '230' - DYNAMIC_EV_ICE_RANGE = '232' - ECO_ROUTE_CALCULATION = '233' - CO_PILOT = '234' - DRIVING_JOURNEY_HISTORY = '235' - NISSAN_RENAULT_BROADCASTS = '241' - ONLINE_PARKING_INFO = '243' - ONLINE_RESTAURANT_INFO = '244' - ONLINE_SPEED_RESTRICTION_INFO = '245' - WEATHER_INFO = '246' - VEHICLE_ACCESS_TO_EMAIL = '248' - VEHICLE_ACCESS_TO_MUSIC = '249' - VEHICLE_ACCESS_TO_CONTACTS = '262' - APP_DOOR_LOCKING = '27' - GLONASS = '276' - ZONE_ALERT = '281' - SPEEDING_ALERT = '282' - SERVICE_SUBSCRIPTION = '284' - PAY_HOW_YOU_DRIVE = '286' - CHARGING_SPOT_INFO = '288' - FLEET_ASSET_INFORMATION = '29' - CHARGING_SPOT_INFO_COLLECTION = '292' - CHARGING_START = '299' - CHARGING_STOP = '303' - INTERIOR_TEMP_SETTINGS = '307' - CLIMATE_ON_OFF_NOTIFICATION = '311' - CHARGING_SPOT_SEARCH = '312' - PLUG_IN_REMINDER = '314' - CHARGING_STOP_NOTIFICATION = '317' - BATTERY_STATUS = '319' - BATTERY_HEATING_NOTIFICATION = '320' - VEHICLE_STATE_OF_CHARGE_PERCENT = '322' - BATTERY_STATE_OF_HEALTH_PERCENT = '323' - PAY_AS_YOU_DRIVE = '34' - DRIVING_ANALYSIS = '340' - CO2_GAS_SAVINGS = '341' - ELECTRICITY_FEE_CALCULATION = '342' - CHARGING_CONSUMPTION_HISTORY = '344' - BATTERY_MONITORING = '345' - BATTERY_DATA = '347' - APP_BASED_NAVIGATION = '35' - CHARGING_SPOT_UPDATES = '354' - RECHARGEABLE_AREA = '358' - NO_CHARGING_SPOT_INFO = '359' - EV_RANGE = '360' - CLIMATE_ON_OFF = '366' - ONLINE_FUEL_STATION_INFO = '367' - DESTINATION_SEND_TO_CAR = '37' - ECALL = '4' - GOOGLE_PLACES_SEARCH = '40' - PREMIUM_TRAFFIC = '43' - AUTO_COLLISION_NOTIFICATION_ACN = '6' - THEFT_BURGLAR_NOTIFICATION_VEHICLE = '7' - ECO_CHALLENGE = '721' - ECO_CHALLENGE_FLEET = '722' - MOBILE_INFORMATION = '74' - URL_PRESET_ON_VEHICLE = '77' - ASSISTED_DESTINATION_SETTING = '78' - CONCIERGE = '79' - PERSONAL_DATA_SYNC = '80' - THEFT_BURGLAR_NOTIFICATION_APP = '87' - STOLEN_VEHICLE_TRACKING_SVT = '9' - REMOTE_ENGINE_START = '96' - HORN_AND_LIGHTS = '97' - CURFEW_ALERT = '98' - TEMPERATURE = '2042' - VALET_PARKING_CALL = '401' - PANIC_CALL = '406' - VIRTUAL_PERSONAL_ASSISTANT = '734' - ALEXA_ONBOARD_ASSISTANT = '736' - SCHEDULED_ROUTE_CLIMATE_CONTROL = '747' - SCHEDULED_ROUTE_CALENDAR_INTERGRATION = '819' - OWNER_MANUAL = '827' - - -class Language(enum.Enum): - """The service requires ISO 639-1 language codes to be mapped back - to ISO 3166-1 country codes. Of course. - """ - - # Bulgarian = Bulgaria - BG = 'BG' - # Czech = Czech Republic - CS = 'CZ' - # Danish = Denmark - DA = 'DK' - # German = Germany - DE = 'DE' - # Greek = Greece - EL = 'GR' - # Spanish = Spain - ES = 'ES' - # Finnish = Finland - FI = 'FI' - # French = France - FR = 'FR' - # Hebrew = Israel - HE = 'IL' - # Croatian = Croatia - HR = 'HR' - # Hungarian = Hungary - HU = 'HU' - # Italian = Italy - IT = 'IT' - # Formal Norwegian = Norway - NB = 'NO' - # Dutch = Netherlands - NL = 'NL' - # Polish = Poland - PL = 'PL' - # Portuguese = Portugal - PT = 'PT' - # Romanian = Romania - RO = 'RO' - # Russian = Russia - RU = 'RU' - # Slovakian = Slovakia - SK = 'SK' - # Slovenian = Slovenia - SI = 'SL' - # Serbian = Serbia - SR = 'RS' - # Swedish = Sweden - SV = 'SE' - # Ukranian = Ukraine - UK = 'UA' - # Default - EN = 'EN' - - -class Order(enum.Enum): - DESC = 'DESC' - ASC = 'ASC' - - -class NotificationCategoryKey(enum.Enum): - ASSISTANCE = 'assistance' - CHARGE_EV = 'chargeev' - CUSTOM = 'custom' - EV_BATTERY = 'EVBattery' - FOTA = 'fota' - GEO_FENCING = 'geofencing' - MAINTENANCE = 'maintenance' - NAVIGATION = 'navigation' - PRIVACY_MODE = 'privacymode' - REMOTE_CONTROL = 'remotecontrol' - RESET = 'RESET' - RGDC = 'rgdcmyze' - SAFETY_AND_SECURITY = 'Safety&Security' - SVT = 'SVT' - - -class NotificationStatus(enum.Enum): - READ = 'READ' - UNREAD = 'UNREAD' - - -class NotificationChannelType(enum.Enum): - PUSH_APP = 'PUSH_APP' - MAIL = 'MAIL' - OFF = '' - SMS = 'SMS' - - NotificationType = collections.namedtuple('NotificationType', ['key', 'title', 'message', 'category']) NotificationCategory = collections.namedtuple('Category', ['key', 'title']) - -class NotificationTypeKey(enum.Enum): - ABS_ALERT = 'abs.alert' - AVAILABLE_CHARGING = 'available.charging' - BADGE_BATTERY_ALERT = 'badge.battery.alert' - BATTERY_BLOWING_REQUEST = 'battery.blowing.request' - BATTERY_CHARGE_AVAILABLE = 'battery.charge.available' - BATTERY_CHARGE_IN_PROGRESS = 'battery.charge.in.progress' - BATTERY_CHARGE_UNAVAILABLE = 'battery.charge.unavailable' - BATTERY_COOLING_CONDITIONNING_REQUEST = 'battery.cooling.conditionning.request' - BATTERY_ENDED_CHARGE = 'battery.ended.charge' - BATTERY_FLAP_OPENED = 'battery.flap.opened' - BATTERY_FULL_EXCEPTION = 'battery.full.exception' - BATTERY_HEATING_CONDITIONNING_REQUEST = 'battery.heating.conditionning.request' - BATTERY_HEATING_START = 'battery.heating.start' - BATTERY_HEATING_STOP = 'battery.heating.stop' - BATTERY_PREHEATING_START = 'battery.preheating.start' - BATTERY_PREHEATING_STOP = 'battery.preheating.stop' - BATTERY_SCHEDULE_ISSUE = 'battery.schedule.issue' - BATTERY_TEMPERATURE_ALERT = 'battery.temperature.alert' - BATTERY_WAITING_CURRENT_CHARGE = 'battery.waiting.current.charge' - BATTERY_WAITING_PLANNED_CHARGE = 'battery.waiting.planned.charge' - BRAKE_ALERT = 'brake.alert' - BRAKE_SYSTEM_MALFUNCTION = 'brake.system.malfunction' - BURGLAR_ALARM_LOST = 'burglar.alarm.lost' - BURGLAR_CAR_STOLEN = 'burglar.car.stolen' - BURGLAR_TOW_INFO = 'burglar.tow.info' - CHARGE_FAILURE = 'charge.failure' - CHARGE_NOT_PROHIBITED = 'charge.not.prohibited' - CHARGE_PROHIBITED = 'charge.prohibited' - CHARGING_STOP_GEN3 = 'charging.stop.gen3' - COOLANT_ALERT = 'coolant.alert' - CRASH_DETECTION_ALERT = 'crash.detection.alert' - CURFEW_INFRINGEMENT = 'curfew.infringement' - CURFEW_RECOVERY = 'curfew.recovery' - CUSTOM = 'custom' - DURING_INHIBITED_CHARGING = 'during.inhibited.charging' - ENGINE_WATER_TEMP_ALERT = 'engine.water.temp.alert' - EPS_ALERT = 'eps.alert' - FOTA_CAMPAIGN_AVAILABLE = 'fota.campaign.available' - FOTA_CAMPAIGN_STATUS_ACTIVATION_COMPLETED = 'fota.campaign.status.activation.completed' - FOTA_CAMPAIGN_STATUS_ACTIVATION_FAILED = 'fota.campaign.status.activation.failed' - FOTA_CAMPAIGN_STATUS_ACTIVATION_POSTPONED = 'fota.campaign.status.activation.postponed' - FOTA_CAMPAIGN_STATUS_ACTIVATION_PROGRESS = 'fota.campaign.status.activation.progress' - FOTA_CAMPAIGN_STATUS_ACTIVATION_SCHEDULED = 'fota.campaign.status.activation.scheduled' - FOTA_CAMPAIGN_STATUS_CANCELLED = 'fota.campaign.status.cancelled' - FOTA_CAMPAIGN_STATUS_CANCELLING = 'fota.campaign.status.cancelling' - FOTA_CAMPAIGN_STATUS_DOWNLOAD_COMPLETED = 'fota.campaign.status.download.completed' - FOTA_CAMPAIGN_STATUS_DOWNLOAD_PAUSED = 'fota.campaign.status.download.paused' - FOTA_CAMPAIGN_STATUS_DOWNLOAD_PROGRESS = 'fota.campaign.status.download.progress' - FOTA_CAMPAIGN_STATUS_INSTALLATION_COMPLETED = 'fota.campaign.status.installation.completed' - FOTA_CAMPAIGN_STATUS_INSTALLATION_PROGRESS = 'fota.campaign.status.installation.progress' - FUEL_ALERT = 'fuel.alert' - HVAC_AUTOSTART = 'hvac.autostart' - HVAC_AUTOSTOP = 'hvac.autostop' - HVAC_TECHNICAL_ISSUE = 'hvac.technical.issue' - HVAC_TRACTION_BATTERY_LOW = 'hvac.traction.battery.low' - HVAC_VEHICLE_IN_USE = 'hvac.vehicle.in.use' - HVAC_VEHICLE_NOT_CONNECTED_POWER = 'hvac.vehicle.not.connected.power' - LAST_MILE_DESTINATION_ADDRESS = 'last.mile.destination.address' - LOCK_STATUS_REMINDER = 'lock.status.reminder' - MAINTENANCE_DISTANCE_PREALERT = 'maintenance.distance.prealert' - MAINTENANCE_TIME_PREALERT = 'maintenance.time.prealert' - MIL_LAMP_AUTO_TEST = 'mil.lamp.auto.test' - MIL_LAMP_FLASH_REQUEST = 'mil.lamp.flash.request' - MIL_LAMP_OFF_REQUEST = 'mil.lamp.off.request' - MIL_LAMP_ON_REQUEST = 'mil.lamp.on.request' - NEXT_CHARGING_INHIBITED = 'next.charging.inhibited' - OIL_LEVEL_ALERT = 'oil.level.alert' - OIL_PRESSURE_ALERT = 'oil.pressure.alert' - OUT_OF_PARK_POSITION_CHARGE_INTERRUPTION = 'out.of.park.position.charge.interruption' - PLUG_CONNECTION_ISSUE = 'plug.connection.issue' - PLUG_CONNECTION_SUCCESS = 'plug.connection.success' - PLUG_UNLOCKING = 'plug.unlocking' - PREREMINDER_ALERT_DEFAULT = 'prereminder.alert.default' - PRIVACY_MODE_OFF = 'privacy.mode.off' - PRIVACY_MODE_ON = 'privacy.mode.on' - PROGRAMMED_CHARGE_INTERRUPTION = 'programmed.charge.interruption' - PROHIBITION_BATTERY_RENTAL = 'prohibition.battery.rental' - PWT_START_IMPOSSIBLE = 'pwt.start.impossible' - REMOTE_LEFT_TIME_CYCLE = 'remote.left.time.cycle' - REMOTE_START_CUSTOMER = 'remote.start.customer' - REMOTE_START_ENGINE = 'remote.start.engine' - REMOTE_START_NORMAL_ONLY = 'remote.start.normal.only' - REMOTE_START_PHONE_ERROR = 'remote.start.phone.error' - REMOTE_START_UNAVAILABLE = 'remote.start.unavailable' - REMOTE_START_WAIT_PRESOAK = 'remote.start.wait.presoak' - SERV_WARNING_ALERT = 'serv.warning.alert' - SPEED_INFRINGEMENT = 'speed.infringement' - SPEED_RECOVERY = 'speed.recovery' - START_DRIVING_CHARGE_INTERRUPTION = 'start.driving.charge.interruption' - START_IN_PROGRESS = 'start.in.progress' - STATUS_OIL_PRESSURE_SWITCH_CLOSED = 'status.oil.pressure.switch.closed' - STATUS_OIL_PRESSURE_SWITCH_OPEN = 'status.oil.pressure.switch.open' - STOP_WARNING_ALERT = 'stop.warning.alert' - UNPLUG_CHARGE = 'unplug.charge' - WAITING_PLANNED_CHARGE = 'waiting.planned.charge' - WHEEL_ALERT = 'wheel.alert' - ZONE_INFRINGEMENT = 'zone.infringement' - ZONE_RECOVERY = 'zone.recovery' - - -class NotificationRuleKey(enum.Enum): - ABS_ALERT = 'abs.alert' - AVAILABLE_CHARGING = 'available.charging' - BADGE_BATTERY_ALERT = 'badge.battery.alert' - BATTERY_BLOWING_REQUEST = 'battery.blowing.request' - BATTERY_CHARGE_AVAILABLE = 'battery.charge.available' - BATTERY_CHARGE_IN_PROGRESS = 'battery.charge.in.progress' - BATTERY_CHARGE_UNAVAILABLE = 'battery.charge.unavailable' - BATTERY_COOLING_CONDITIONNING_REQUEST = 'battery.cooling.conditionning.request' - BATTERY_ENDED_CHARGE = 'battery.ended.charge' - BATTERY_FLAP_OPENED = 'battery.flap.opened' - BATTERY_FULL_EXCEPTION = 'battery.full.exception' - BATTERY_HEATING_CONDITIONNING_REQUEST = 'battery.heating.conditionning.request' - BATTERY_HEATING_START = 'battery.heating.start' - BATTERY_HEATING_STOP = 'battery.heating.stop' - BATTERY_PREHEATING_START = 'battery.preheating.start' - BATTERY_PREHEATING_STOP = 'battery.preheating.stop' - BATTERY_SCHEDULE_ISSUE = 'battery.schedule.issue' - BATTERY_TEMPERATURE_ALERT = 'battery.temperature.alert' - BATTERY_WAITING_CURRENT_CHARGE = 'battery.waiting.current.charge' - BATTERY_WAITING_PLANNED_CHARGE = 'battery.waiting.planned.charge' - BRAKE_ALERT = 'brake.alert' - BRAKE_SYSTEM_MALFUNCTION = 'brake.system.malfunction' - BURGLAR_ALARM_LOST = 'burglar.alarm.lost' - BURGLAR_CAR_STOLEN = 'burglar.car.stolen' - BURGLAR_TOW_INFO = 'burglar.tow.info' - BURGLAR_TOW_SYSTEM_FAILURE = 'burglar.tow.system.failure' - CHARGE_FAILURE = 'charge.failure' - CHARGE_NOT_PROHIBITED = 'charge.not.prohibited' - CHARGE_PROHIBITED = 'charge.prohibited' - CHARGING_STOP_GEN3 = 'charging.stop.gen3' - COOLANT_ALERT = 'coolant.alert' - CRASH_DETECTION_ALERT = 'crash.detection.alert' - CURFEW_INFRINGEMENT = 'curfew.infringement' - CURFEW_RECOVERY = 'curfew.recovery' - CUSTOM = 'custom' - DURING_INHIBITED_CHARGING = 'during.inhibited.charging' - ENGINE_WATER_TEMP_ALERT = 'engine.water.temp.alert' - EPS_ALERT = 'eps.alert' - FOTA_CAMPAIGN_AVAILABLE = 'fota.campaign.available' - FOTA_CAMPAIGN_STATUS_ACTIVATION_COMPLETED = 'fota.campaign.status.activation.completed' - FOTA_CAMPAIGN_STATUS_ACTIVATION_FAILED = 'fota.campaign.status.activation.failed' - FOTA_CAMPAIGN_STATUS_ACTIVATION_POSTPONED = 'fota.campaign.status.activation.postponed' - FOTA_CAMPAIGN_STATUS_ACTIVATION_PROGRESS = 'fota.campaign.status.activation.progress' - FOTA_CAMPAIGN_STATUS_ACTIVATION_SCHEDULED = 'fota.campaign.status.activation.scheduled' - FOTA_CAMPAIGN_STATUS_CANCELLED = 'fota.campaign.status.cancelled' - FOTA_CAMPAIGN_STATUS_CANCELLING = 'fota.campaign.status.cancelling' - FOTA_CAMPAIGN_STATUS_DOWNLOAD_COMPLETED = 'fota.campaign.status.download.completed' - FOTA_CAMPAIGN_STATUS_DOWNLOAD_PAUSED = 'fota.campaign.status.download.paused' - FOTA_CAMPAIGN_STATUS_DOWNLOAD_PROGRESS = 'fota.campaign.status.download.progress' - FOTA_CAMPAIGN_STATUS_INSTALLATION_COMPLETED = 'fota.campaign.status.installation.completed' - FOTA_CAMPAIGN_STATUS_INSTALLATION_PROGRESS = 'fota.campaign.status.installation.progress' - FUEL_ALERT = 'fuel.alert' - HVAC_AUTOSTART = 'hvac.autostart' - HVAC_AUTOSTOP = 'hvac.autostop' - HVAC_TECHNICAL_ISSUE = 'hvac.technical.issue' - HVAC_TRACTION_BATTERY_LOW = 'hvac.traction.battery.low' - HVAC_VEHICLE_IN_USE = 'hvac.vehicle.in.use' - HVAC_VEHICLE_NOT_CONNECTED_POWER = 'hvac.vehicle.not.connected.power' - LAST_MILE_DESTINATION_ADDRESS = 'last.mile.destination.address' - LOCK_STATUS_REMINDER = 'lock.status.reminder' - MAINTENANCE_DISTANCE_PREALERT = 'maintenance.distance.prealert' - MAINTENANCE_TIME_PREALERT = 'maintenance.time.prealert' - MIL_LAMP_AUTO_TEST = 'mil.lamp.auto.test' - MIL_LAMP_FLASH_REQUEST = 'mil.lamp.flash.request' - MIL_LAMP_OFF_REQUEST = 'mil.lamp.off.request' - MIL_LAMP_ON_REQUEST = 'mil.lamp.on.request' - NEXT_CHARGING_INHIBITED = 'next.charging.inhibited' - OIL_LEVEL_ALERT = 'oil.level.alert' - OIL_PRESSURE_ALERT = 'oil.pressure.alert' - OUT_OF_PARK_POSITION_CHARGE_INTERRUPTION = 'out.of.park.position.charge.interruption' - PLUG_CONNECTION_ISSUE = 'plug.connection.issue' - PLUG_CONNECTION_SUCCESS = 'plug.connection.success' - PLUG_UNLOCKING = 'plug.unlocking' - PREREMINDER_ALERT_DEFAULT = 'prereminder.alert.default' - PRIVACY_MODE_OFF = 'privacy.mode.off' - PRIVACY_MODE_ON = 'privacy.mode.on' - PROGRAMMED_CHARGE_INTERRUPTION = 'programmed.charge.interruption' - PROHIBITION_BATTERY_RENTAL = 'prohibition.battery.rental' - PWT_START_IMPOSSIBLE = 'pwt.start.impossible' - REMOTE_LEFT_TIME_CYCLE = 'remote.left.time.cycle' - REMOTE_START_CUSTOMER = 'remote.start.customer' - REMOTE_START_ENGINE = 'remote.start.engine' - REMOTE_START_NORMAL_ONLY = 'remote.start.normal.only' - REMOTE_START_PHONE_ERROR = 'remote.start.phone.error' - REMOTE_START_UNAVAILABLE = 'remote.start.unavailable' - REMOTE_START_WAIT_PRESOAK = 'remote.start.wait.presoak' - RENAULT_RESET_FACTORY = 'renault.reset.factory' - RGDC_CHARGE_COMPLETE = 'rgdc.charge.complete' - RGDC_CHARGE_ERROR = 'rgdc.charge.error' - RGDC_CHARGE_ON = 'rgdc.charge.on' - RGDC_CHARGE_STATUS = 'rgdc.charge.status' - RGDC_LOW_BATTERY_ALERT = 'rgdc.low.battery.alert' - RGDC_LOW_BATTERY_REMINDER = 'rgdc.low.battery.reminder' - SERV_WARNING_ALERT = 'serv.warning.alert' - SPEED_INFRINGEMENT = 'speed.infringement' - SPEED_RECOVERY = 'speed.recovery' - SRP_PINCODE_ACKNOWLEDGEMENT = 'srp.pincode.acknowledgement' - SRP_PINCODE_DELETION = 'srp.pincode.deletion' - SRP_PINCODE_STATUS = 'srp.pincode.status' - SRP_SALT_REQUEST = 'srp.salt.request' - START_DRIVING_CHARGE_INTERRUPTION = 'start.driving.charge.interruption' - START_IN_PROGRESS = 'start.in.progress' - STATUS_OIL_PRESSURE_SWITCH_CLOSED = 'status.oil.pressure.switch.closed' - STATUS_OIL_PRESSURE_SWITCH_OPEN = 'status.oil.pressure.switch.open' - STOLEN_VEHICLE_TRACKING = 'stolen.vehicle.tracking' - STOLEN_VEHICLE_TRACKING_BLOCKING = 'stolen.vehicle.tracking.blocking' - STOP_WARNING_ALERT = 'stop.warning.alert' - SVT_SERVICE_ACTIVATION = 'svt.service.activation' - UNPLUG_CHARGE = 'unplug.charge' - WAITING_PLANNED_CHARGE = 'waiting.planned.charge' - WHEEL_ALERT = 'wheel.alert' - ZONE_INFRINGEMENT = 'zone.infringement' - ZONE_RECOVERY = 'zone.recovery' - - -class NotificationPriority(enum.Enum): - - NONE = None - P0 = 0 - P1 = 1 - P2 = 2 - P3 = 3 - - -class NotificationRuleStatus(enum.Enum): - ACTIVATED = 'ACTIVATED' - ACTIVATION_IN_PROGRESS = 'STATUS_ACTIVATION_IN_PROGRESS' - DELETION_IN_PROGRESS = 'STATUS_DELETION_IN_PROGRESS' - - class Notification: @property @@ -608,7 +87,7 @@ class KamereonSession: unique_id = None def __init__(self, region, unique_id=None): - self.settings = settings_map[self.tenant][region] + self.settings = SETTINGS_MAP[self.tenant][region] session = requests.session() self.session = session self._oauth = None @@ -743,7 +222,7 @@ def __repr__(self): return '<{} {}>'.format(self.__class__.__name__, self.vin) def __str__(self): - return self.nickname or self.vin + return self.vin @property def session(self): @@ -763,7 +242,7 @@ def __init__(self, data, user_id): _LOGGER.debug(f"Unknown feature {str(u['id'])}") pass - _LOGGER.debug(f"Active features: {self.features}") + _LOGGER.debug("Active features: %s", self.features) self.can_generation = data.get('canGeneration') self.color = data.get('color') @@ -1137,7 +616,7 @@ def fetch_hvac_status(self): self.internal_temperature = hvac_data.get('internalTemperature') self.next_target_temperature = hvac_data.get('nextTargetTemperature') if 'hvacStatus' in hvac_data: - self.hvac_status = HVACStatus(hvac_data['hvacStatus']) + self.hvac_status = hvac_data['hvacStatus'] == "on" if 'nextHvacStartDate' in hvac_data: self.next_hvac_start_date = datetime.datetime.fromisoformat(hvac_data['nextHvacStartDate'].replace('Z','+00:00')) if 'lastUpdateTime' in hvac_data: @@ -1157,10 +636,14 @@ def refresh_battery_status(self): return body def fetch_battery_status(self): + if self.model_name == "Ariya": + return self.fetch_battery_status_ariya() + + return self.fetch_battery_status_leaf() + + def fetch_battery_status_leaf(self): """The battery-status endpoint isn't just for EV's. ICE Nissans publish the range under this! There is no obvious feature to qualify this, so we just suck it and see.""" - if not self.battery_supported and Feature.BATTERY_STATUS not in self.features: - return resp = self._get( '{}v1/cars/{}/battery-status'.format(self.session.settings['car_adapter_base_url'], self.vin), headers={'Content-Type': 'application/vnd.api+json'} @@ -1202,6 +685,49 @@ def fetch_battery_status(self): if 'lastUpdateTime' in battery_data: self.battery_status_last_updated = datetime.datetime.fromisoformat(battery_data['lastUpdateTime'].replace('Z','+00:00')) + def fetch_battery_status_ariya(self): + resp = self._get( + '{}v3/cars/{}/battery-status?canGen={}'.format(self.session.settings['user_base_url'], self.vin, self.can_generation), + headers={'Content-Type': 'application/vnd.api+json'} + ) + body = resp.json() + if 'errors' in body and Feature.BATTERY_STATUS in self.features: + raise ValueError(body['errors']) + + if not 'data' in body or not 'attributes' in body['data']: + self.battery_supported = False + + battery_data = body['data']['attributes'] + self.battery_capacity = battery_data.get('batteryCapacity') # kWh + self.battery_level = battery_data.get('batteryLevel') # % + self.battery_temperature = battery_data.get('batteryTemperature') # Fahrenheit? + # same meaning as battery level, different scale. 240 = 100% + self.battery_bar_level = battery_data.get('batteryBarLevel') + self.instantaneous_power = battery_data.get('instantaneousPower') # kW + self.charging_speed = ChargingSpeed(None) + self.charge_time_required_to_full = { + ChargingSpeed.FAST: battery_data.get('chargingRemainingTime'), + ChargingSpeed.NORMAL: battery_data.get('chargingRemainingTime'), + ChargingSpeed.SLOW: battery_data.get('chargingRemainingTime'), + } + self.range_hvac_off = battery_data.get('batteryAutonomy') + self.range_hvac_on = battery_data.get('batteryAutonomy') + + # For ICE vehicles, we should get the range at least. If not, dont bother again + if self.range_hvac_on is None and Feature.BATTERY_STATUS not in self.features: + self.battery_supported = False + return + + self.plugged_in = PluggedStatus(battery_data.get('plugStatus', 0)) + if self.plugged_in == PluggedStatus(1): + self.charging = ChargingStatus(battery_data.get('chargeStatus', 0)) + + if 'vehiclePlugTimestamp' in battery_data: + self.plugged_in_time = datetime.datetime.fromisoformat(battery_data['vehiclePlugTimestamp'].replace('Z','+00:00')) + if 'vehicleUnplugTimestamp' in battery_data: + self.unplugged_time = datetime.datetime.fromisoformat(battery_data['vehicleUnplugTimestamp'].replace('Z','+00:00')) + if 'lastUpdateTime' in battery_data: + self.battery_status_last_updated = datetime.datetime.fromisoformat(battery_data['lastUpdateTime'].replace('Z','+00:00')) def set_energy_unit_cost(self, cost): resp = self._post( diff --git a/custom_components/nissan_connect/kamereon/kamereon_const.py b/custom_components/nissan_connect/kamereon/kamereon_const.py new file mode 100644 index 0000000..a41eb2f --- /dev/null +++ b/custom_components/nissan_connect/kamereon/kamereon_const.py @@ -0,0 +1,500 @@ +import enum + +API_VERSION = 'protocol=1.0,resource=2.1' +SRP_KEY = 'D5AF0E14718E662D12DBB4FE42304DF5A8E48359E22261138B40AA16CC85C76A11B43200A1EECB3C9546A262D1FBD51ACE6FCDE558C00665BBF93FF86B9F8F76AA7A53CA74F5B4DFF9A4B847295E7D82450A2078B5A28814A7A07F8BBDD34F8EEB42B0E70499087A242AA2C5BA9513C8F9D35A81B33A121EEF0A71F3F9071CCD' + +SETTINGS_MAP = { + 'nissan': { + 'EU': { + 'client_id': 'a-ncb-nc-android-prod', + 'client_secret': '6GKIax7fGT5yPHuNmWNVOc4q5POBw1WRSW39ubRA8WPBmQ7MOxhm75EsmKMKENem', + 'scope': 'openid profile vehicles', + 'auth_base_url': 'https://prod.eu2.auth.kamereon.org/kauth/', + 'realm': 'a-ncb-prod', + 'redirect_uri': 'org.kamereon.service.nci:/oauth2redirect', + 'car_adapter_base_url': 'https://alliance-platform-caradapter-prod.apps.eu2.kamereon.io/car-adapter/', + 'notifications_base_url': 'https://alliance-platform-notifications-prod.apps.eu2.kamereon.io/notifications/', + 'user_adapter_base_url': 'https://alliance-platform-usersadapter-prod.apps.eu2.kamereon.io/user-adapter/', + 'user_base_url': 'https://nci-bff-web-prod.apps.eu2.kamereon.io/bff-web/' + } + } +} + + +USERS = 'users' +VEHICLES = 'vehicles' +CATEGORIES = 'categories' +NOTIFICATION_RULES = 'notification_rules' +NOTIFICATION_TYPES = 'notification_types' +NOTIFICATION_CATEGORIES = 'notification_categories' + +class HVACAction(enum.Enum): + # Start or schedule start + START = 'start' + # Stop active HVAC + STOP = 'stop' + # Cancel scheduled HVAC + CANCEL = 'cancel' + + +class LockStatus(enum.Enum): + CLOSED = 'closed' + LOCKED = 'locked' + OPEN = 'open' + UNLOCKED = 'unlocked' + + +class Door(enum.Enum): + HATCH = 'hatch' + FRONT_LEFT = 'front_left' + FRONT_RIGHT = 'front_right' + REAR_LEFT = 'rear_left' + REAR_RIGHT = 'rear_right' + + +class LockableDoorGroup(enum.Enum): + DOORS_AND_HATCH = 'doors_hatch' + DRIVERS_DOOR = 'driver_s_door' + HATCH = 'hatch' + + +class ChargingSpeed(enum.Enum): + NONE = None + SLOW = 1 + NORMAL = 2 + FAST = 3 + FASTEST = 4 + + +class ChargingStatus(enum.Enum): + ERROR = -1 + NOT_CHARGING = 0 + CHARGING = 1 + + +class PluggedStatus(enum.Enum): + ERROR = -1 + NOT_PLUGGED = 0 + PLUGGED = 1 + + +class Period(enum.Enum): + DAILY = 0 + MONTHLY = 1 + YEARLY = 2 + + +class Feature(enum.Enum): + BREAKDOWN_ASSISTANCE_CALL = '1' + SVT_WITH_VEHICLE_BLOCKAGE = '10' + MAINTENANCE_ALERT = '101' + VEHICLE_SOFTWARE_UPDATES = '107' + MY_CAR_FINDER = '12' + MIL_ON_NOTIFICATION = '15' + VEHICLE_HEALTH_REPORT = '18' + ADVANCED_CAN = '201' + VEHICLE_STATUS_CHECK = '202' + LOCK_STATUS_CHECK = '2021' + NAVIGATION_FACTORY_RESET = '208' + MESSAGES_TO_THE_VEHICLE = '21' + VEHICLE_DATA = '2121' + VEHICLE_DATA_2 = '2122' + VEHICLE_WIFI = '213' + ADVANCED_VEHICLE_DIAGNOSTICS = '215' + NAVIGATION_MAP_UPDATES = '217' + VEHICLE_SETTINGS_TRANSFER = '221' + LAST_MILE_NAVIGATION = '227' + GOOGLE_STREET_VIEW = '229' + GOOGLE_SATELITE_VIEW = '230' + DYNAMIC_EV_ICE_RANGE = '232' + ECO_ROUTE_CALCULATION = '233' + CO_PILOT = '234' + DRIVING_JOURNEY_HISTORY = '235' + NISSAN_RENAULT_BROADCASTS = '241' + ONLINE_PARKING_INFO = '243' + ONLINE_RESTAURANT_INFO = '244' + ONLINE_SPEED_RESTRICTION_INFO = '245' + WEATHER_INFO = '246' + VEHICLE_ACCESS_TO_EMAIL = '248' + VEHICLE_ACCESS_TO_MUSIC = '249' + VEHICLE_ACCESS_TO_CONTACTS = '262' + APP_DOOR_LOCKING = '27' + GLONASS = '276' + ZONE_ALERT = '281' + SPEEDING_ALERT = '282' + SERVICE_SUBSCRIPTION = '284' + PAY_HOW_YOU_DRIVE = '286' + CHARGING_SPOT_INFO = '288' + FLEET_ASSET_INFORMATION = '29' + CHARGING_SPOT_INFO_COLLECTION = '292' + CHARGING_START = '299' + CHARGING_STOP = '303' + INTERIOR_TEMP_SETTINGS = '307' + CLIMATE_ON_OFF_NOTIFICATION = '311' + CHARGING_SPOT_SEARCH = '312' + PLUG_IN_REMINDER = '314' + CHARGING_STOP_NOTIFICATION = '317' + BATTERY_STATUS = '319' + BATTERY_HEATING_NOTIFICATION = '320' + VEHICLE_STATE_OF_CHARGE_PERCENT = '322' + BATTERY_STATE_OF_HEALTH_PERCENT = '323' + PAY_AS_YOU_DRIVE = '34' + DRIVING_ANALYSIS = '340' + CO2_GAS_SAVINGS = '341' + ELECTRICITY_FEE_CALCULATION = '342' + CHARGING_CONSUMPTION_HISTORY = '344' + BATTERY_MONITORING = '345' + BATTERY_DATA = '347' + APP_BASED_NAVIGATION = '35' + CHARGING_SPOT_UPDATES = '354' + RECHARGEABLE_AREA = '358' + NO_CHARGING_SPOT_INFO = '359' + EV_RANGE = '360' + CLIMATE_ON_OFF = '366' + ONLINE_FUEL_STATION_INFO = '367' + DESTINATION_SEND_TO_CAR = '37' + ECALL = '4' + GOOGLE_PLACES_SEARCH = '40' + PREMIUM_TRAFFIC = '43' + AUTO_COLLISION_NOTIFICATION_ACN = '6' + THEFT_BURGLAR_NOTIFICATION_VEHICLE = '7' + ECO_CHALLENGE = '721' + ECO_CHALLENGE_FLEET = '722' + MOBILE_INFORMATION = '74' + URL_PRESET_ON_VEHICLE = '77' + ASSISTED_DESTINATION_SETTING = '78' + CONCIERGE = '79' + PERSONAL_DATA_SYNC = '80' + THEFT_BURGLAR_NOTIFICATION_APP = '87' + STOLEN_VEHICLE_TRACKING_SVT = '9' + REMOTE_ENGINE_START = '96' + HORN_AND_LIGHTS = '97' + CURFEW_ALERT = '98' + TEMPERATURE = '2042' + VALET_PARKING_CALL = '401' + PANIC_CALL = '406' + VIRTUAL_PERSONAL_ASSISTANT = '734' + ALEXA_ONBOARD_ASSISTANT = '736' + SCHEDULED_ROUTE_CLIMATE_CONTROL = '747' + SCHEDULED_ROUTE_CALENDAR_INTERGRATION = '819' + OWNER_MANUAL = '827' + + +class Language(enum.Enum): + """The service requires ISO 639-1 language codes to be mapped back + to ISO 3166-1 country codes. Of course. + """ + + # Bulgarian = Bulgaria + BG = 'BG' + # Czech = Czech Republic + CS = 'CZ' + # Danish = Denmark + DA = 'DK' + # German = Germany + DE = 'DE' + # Greek = Greece + EL = 'GR' + # Spanish = Spain + ES = 'ES' + # Finnish = Finland + FI = 'FI' + # French = France + FR = 'FR' + # Hebrew = Israel + HE = 'IL' + # Croatian = Croatia + HR = 'HR' + # Hungarian = Hungary + HU = 'HU' + # Italian = Italy + IT = 'IT' + # Formal Norwegian = Norway + NB = 'NO' + # Dutch = Netherlands + NL = 'NL' + # Polish = Poland + PL = 'PL' + # Portuguese = Portugal + PT = 'PT' + # Romanian = Romania + RO = 'RO' + # Russian = Russia + RU = 'RU' + # Slovakian = Slovakia + SK = 'SK' + # Slovenian = Slovenia + SI = 'SL' + # Serbian = Serbia + SR = 'RS' + # Swedish = Sweden + SV = 'SE' + # Ukranian = Ukraine + UK = 'UA' + # Default + EN = 'EN' + + +class Order(enum.Enum): + DESC = 'DESC' + ASC = 'ASC' + + +class NotificationCategoryKey(enum.Enum): + ASSISTANCE = 'assistance' + CHARGE_EV = 'chargeev' + CUSTOM = 'custom' + EV_BATTERY = 'EVBattery' + FOTA = 'fota' + GEO_FENCING = 'geofencing' + MAINTENANCE = 'maintenance' + NAVIGATION = 'navigation' + PRIVACY_MODE = 'privacymode' + REMOTE_CONTROL = 'remotecontrol' + RESET = 'RESET' + RGDC = 'rgdcmyze' + SAFETY_AND_SECURITY = 'Safety&Security' + SVT = 'SVT' + + +class NotificationStatus(enum.Enum): + READ = 'READ' + UNREAD = 'UNREAD' + + +class NotificationChannelType(enum.Enum): + PUSH_APP = 'PUSH_APP' + MAIL = 'MAIL' + OFF = '' + SMS = 'SMS' + +class NotificationTypeKey(enum.Enum): + ABS_ALERT = 'abs.alert' + AVAILABLE_CHARGING = 'available.charging' + BADGE_BATTERY_ALERT = 'badge.battery.alert' + BATTERY_BLOWING_REQUEST = 'battery.blowing.request' + BATTERY_CHARGE_AVAILABLE = 'battery.charge.available' + BATTERY_CHARGE_IN_PROGRESS = 'battery.charge.in.progress' + BATTERY_CHARGE_UNAVAILABLE = 'battery.charge.unavailable' + BATTERY_COOLING_CONDITIONNING_REQUEST = 'battery.cooling.conditionning.request' + BATTERY_ENDED_CHARGE = 'battery.ended.charge' + BATTERY_FLAP_OPENED = 'battery.flap.opened' + BATTERY_FULL_EXCEPTION = 'battery.full.exception' + BATTERY_HEATING_CONDITIONNING_REQUEST = 'battery.heating.conditionning.request' + BATTERY_HEATING_START = 'battery.heating.start' + BATTERY_HEATING_STOP = 'battery.heating.stop' + BATTERY_PREHEATING_START = 'battery.preheating.start' + BATTERY_PREHEATING_STOP = 'battery.preheating.stop' + BATTERY_SCHEDULE_ISSUE = 'battery.schedule.issue' + BATTERY_TEMPERATURE_ALERT = 'battery.temperature.alert' + BATTERY_WAITING_CURRENT_CHARGE = 'battery.waiting.current.charge' + BATTERY_WAITING_PLANNED_CHARGE = 'battery.waiting.planned.charge' + BRAKE_ALERT = 'brake.alert' + BRAKE_SYSTEM_MALFUNCTION = 'brake.system.malfunction' + BURGLAR_ALARM_LOST = 'burglar.alarm.lost' + BURGLAR_CAR_STOLEN = 'burglar.car.stolen' + BURGLAR_TOW_INFO = 'burglar.tow.info' + CHARGE_FAILURE = 'charge.failure' + CHARGE_NOT_PROHIBITED = 'charge.not.prohibited' + CHARGE_PROHIBITED = 'charge.prohibited' + CHARGING_STOP_GEN3 = 'charging.stop.gen3' + COOLANT_ALERT = 'coolant.alert' + CRASH_DETECTION_ALERT = 'crash.detection.alert' + CURFEW_INFRINGEMENT = 'curfew.infringement' + CURFEW_RECOVERY = 'curfew.recovery' + CUSTOM = 'custom' + DURING_INHIBITED_CHARGING = 'during.inhibited.charging' + ENGINE_WATER_TEMP_ALERT = 'engine.water.temp.alert' + EPS_ALERT = 'eps.alert' + FOTA_CAMPAIGN_AVAILABLE = 'fota.campaign.available' + FOTA_CAMPAIGN_STATUS_ACTIVATION_COMPLETED = 'fota.campaign.status.activation.completed' + FOTA_CAMPAIGN_STATUS_ACTIVATION_FAILED = 'fota.campaign.status.activation.failed' + FOTA_CAMPAIGN_STATUS_ACTIVATION_POSTPONED = 'fota.campaign.status.activation.postponed' + FOTA_CAMPAIGN_STATUS_ACTIVATION_PROGRESS = 'fota.campaign.status.activation.progress' + FOTA_CAMPAIGN_STATUS_ACTIVATION_SCHEDULED = 'fota.campaign.status.activation.scheduled' + FOTA_CAMPAIGN_STATUS_CANCELLED = 'fota.campaign.status.cancelled' + FOTA_CAMPAIGN_STATUS_CANCELLING = 'fota.campaign.status.cancelling' + FOTA_CAMPAIGN_STATUS_DOWNLOAD_COMPLETED = 'fota.campaign.status.download.completed' + FOTA_CAMPAIGN_STATUS_DOWNLOAD_PAUSED = 'fota.campaign.status.download.paused' + FOTA_CAMPAIGN_STATUS_DOWNLOAD_PROGRESS = 'fota.campaign.status.download.progress' + FOTA_CAMPAIGN_STATUS_INSTALLATION_COMPLETED = 'fota.campaign.status.installation.completed' + FOTA_CAMPAIGN_STATUS_INSTALLATION_PROGRESS = 'fota.campaign.status.installation.progress' + FUEL_ALERT = 'fuel.alert' + HVAC_AUTOSTART = 'hvac.autostart' + HVAC_AUTOSTOP = 'hvac.autostop' + HVAC_TECHNICAL_ISSUE = 'hvac.technical.issue' + HVAC_TRACTION_BATTERY_LOW = 'hvac.traction.battery.low' + HVAC_VEHICLE_IN_USE = 'hvac.vehicle.in.use' + HVAC_VEHICLE_NOT_CONNECTED_POWER = 'hvac.vehicle.not.connected.power' + LAST_MILE_DESTINATION_ADDRESS = 'last.mile.destination.address' + LOCK_STATUS_REMINDER = 'lock.status.reminder' + MAINTENANCE_DISTANCE_PREALERT = 'maintenance.distance.prealert' + MAINTENANCE_TIME_PREALERT = 'maintenance.time.prealert' + MIL_LAMP_AUTO_TEST = 'mil.lamp.auto.test' + MIL_LAMP_FLASH_REQUEST = 'mil.lamp.flash.request' + MIL_LAMP_OFF_REQUEST = 'mil.lamp.off.request' + MIL_LAMP_ON_REQUEST = 'mil.lamp.on.request' + NEXT_CHARGING_INHIBITED = 'next.charging.inhibited' + OIL_LEVEL_ALERT = 'oil.level.alert' + OIL_PRESSURE_ALERT = 'oil.pressure.alert' + OUT_OF_PARK_POSITION_CHARGE_INTERRUPTION = 'out.of.park.position.charge.interruption' + PLUG_CONNECTION_ISSUE = 'plug.connection.issue' + PLUG_CONNECTION_SUCCESS = 'plug.connection.success' + PLUG_UNLOCKING = 'plug.unlocking' + PREREMINDER_ALERT_DEFAULT = 'prereminder.alert.default' + PRIVACY_MODE_OFF = 'privacy.mode.off' + PRIVACY_MODE_ON = 'privacy.mode.on' + PROGRAMMED_CHARGE_INTERRUPTION = 'programmed.charge.interruption' + PROHIBITION_BATTERY_RENTAL = 'prohibition.battery.rental' + PWT_START_IMPOSSIBLE = 'pwt.start.impossible' + REMOTE_LEFT_TIME_CYCLE = 'remote.left.time.cycle' + REMOTE_START_CUSTOMER = 'remote.start.customer' + REMOTE_START_ENGINE = 'remote.start.engine' + REMOTE_START_NORMAL_ONLY = 'remote.start.normal.only' + REMOTE_START_PHONE_ERROR = 'remote.start.phone.error' + REMOTE_START_UNAVAILABLE = 'remote.start.unavailable' + REMOTE_START_WAIT_PRESOAK = 'remote.start.wait.presoak' + SERV_WARNING_ALERT = 'serv.warning.alert' + SPEED_INFRINGEMENT = 'speed.infringement' + SPEED_RECOVERY = 'speed.recovery' + START_DRIVING_CHARGE_INTERRUPTION = 'start.driving.charge.interruption' + START_IN_PROGRESS = 'start.in.progress' + STATUS_OIL_PRESSURE_SWITCH_CLOSED = 'status.oil.pressure.switch.closed' + STATUS_OIL_PRESSURE_SWITCH_OPEN = 'status.oil.pressure.switch.open' + STOP_WARNING_ALERT = 'stop.warning.alert' + UNPLUG_CHARGE = 'unplug.charge' + WAITING_PLANNED_CHARGE = 'waiting.planned.charge' + WHEEL_ALERT = 'wheel.alert' + ZONE_INFRINGEMENT = 'zone.infringement' + ZONE_RECOVERY = 'zone.recovery' + + +class NotificationRuleKey(enum.Enum): + ABS_ALERT = 'abs.alert' + AVAILABLE_CHARGING = 'available.charging' + BADGE_BATTERY_ALERT = 'badge.battery.alert' + BATTERY_BLOWING_REQUEST = 'battery.blowing.request' + BATTERY_CHARGE_AVAILABLE = 'battery.charge.available' + BATTERY_CHARGE_IN_PROGRESS = 'battery.charge.in.progress' + BATTERY_CHARGE_UNAVAILABLE = 'battery.charge.unavailable' + BATTERY_COOLING_CONDITIONNING_REQUEST = 'battery.cooling.conditionning.request' + BATTERY_ENDED_CHARGE = 'battery.ended.charge' + BATTERY_FLAP_OPENED = 'battery.flap.opened' + BATTERY_FULL_EXCEPTION = 'battery.full.exception' + BATTERY_HEATING_CONDITIONNING_REQUEST = 'battery.heating.conditionning.request' + BATTERY_HEATING_START = 'battery.heating.start' + BATTERY_HEATING_STOP = 'battery.heating.stop' + BATTERY_PREHEATING_START = 'battery.preheating.start' + BATTERY_PREHEATING_STOP = 'battery.preheating.stop' + BATTERY_SCHEDULE_ISSUE = 'battery.schedule.issue' + BATTERY_TEMPERATURE_ALERT = 'battery.temperature.alert' + BATTERY_WAITING_CURRENT_CHARGE = 'battery.waiting.current.charge' + BATTERY_WAITING_PLANNED_CHARGE = 'battery.waiting.planned.charge' + BRAKE_ALERT = 'brake.alert' + BRAKE_SYSTEM_MALFUNCTION = 'brake.system.malfunction' + BURGLAR_ALARM_LOST = 'burglar.alarm.lost' + BURGLAR_CAR_STOLEN = 'burglar.car.stolen' + BURGLAR_TOW_INFO = 'burglar.tow.info' + BURGLAR_TOW_SYSTEM_FAILURE = 'burglar.tow.system.failure' + CHARGE_FAILURE = 'charge.failure' + CHARGE_NOT_PROHIBITED = 'charge.not.prohibited' + CHARGE_PROHIBITED = 'charge.prohibited' + CHARGING_STOP_GEN3 = 'charging.stop.gen3' + COOLANT_ALERT = 'coolant.alert' + CRASH_DETECTION_ALERT = 'crash.detection.alert' + CURFEW_INFRINGEMENT = 'curfew.infringement' + CURFEW_RECOVERY = 'curfew.recovery' + CUSTOM = 'custom' + DURING_INHIBITED_CHARGING = 'during.inhibited.charging' + ENGINE_WATER_TEMP_ALERT = 'engine.water.temp.alert' + EPS_ALERT = 'eps.alert' + FOTA_CAMPAIGN_AVAILABLE = 'fota.campaign.available' + FOTA_CAMPAIGN_STATUS_ACTIVATION_COMPLETED = 'fota.campaign.status.activation.completed' + FOTA_CAMPAIGN_STATUS_ACTIVATION_FAILED = 'fota.campaign.status.activation.failed' + FOTA_CAMPAIGN_STATUS_ACTIVATION_POSTPONED = 'fota.campaign.status.activation.postponed' + FOTA_CAMPAIGN_STATUS_ACTIVATION_PROGRESS = 'fota.campaign.status.activation.progress' + FOTA_CAMPAIGN_STATUS_ACTIVATION_SCHEDULED = 'fota.campaign.status.activation.scheduled' + FOTA_CAMPAIGN_STATUS_CANCELLED = 'fota.campaign.status.cancelled' + FOTA_CAMPAIGN_STATUS_CANCELLING = 'fota.campaign.status.cancelling' + FOTA_CAMPAIGN_STATUS_DOWNLOAD_COMPLETED = 'fota.campaign.status.download.completed' + FOTA_CAMPAIGN_STATUS_DOWNLOAD_PAUSED = 'fota.campaign.status.download.paused' + FOTA_CAMPAIGN_STATUS_DOWNLOAD_PROGRESS = 'fota.campaign.status.download.progress' + FOTA_CAMPAIGN_STATUS_INSTALLATION_COMPLETED = 'fota.campaign.status.installation.completed' + FOTA_CAMPAIGN_STATUS_INSTALLATION_PROGRESS = 'fota.campaign.status.installation.progress' + FUEL_ALERT = 'fuel.alert' + HVAC_AUTOSTART = 'hvac.autostart' + HVAC_AUTOSTOP = 'hvac.autostop' + HVAC_TECHNICAL_ISSUE = 'hvac.technical.issue' + HVAC_TRACTION_BATTERY_LOW = 'hvac.traction.battery.low' + HVAC_VEHICLE_IN_USE = 'hvac.vehicle.in.use' + HVAC_VEHICLE_NOT_CONNECTED_POWER = 'hvac.vehicle.not.connected.power' + LAST_MILE_DESTINATION_ADDRESS = 'last.mile.destination.address' + LOCK_STATUS_REMINDER = 'lock.status.reminder' + MAINTENANCE_DISTANCE_PREALERT = 'maintenance.distance.prealert' + MAINTENANCE_TIME_PREALERT = 'maintenance.time.prealert' + MIL_LAMP_AUTO_TEST = 'mil.lamp.auto.test' + MIL_LAMP_FLASH_REQUEST = 'mil.lamp.flash.request' + MIL_LAMP_OFF_REQUEST = 'mil.lamp.off.request' + MIL_LAMP_ON_REQUEST = 'mil.lamp.on.request' + NEXT_CHARGING_INHIBITED = 'next.charging.inhibited' + OIL_LEVEL_ALERT = 'oil.level.alert' + OIL_PRESSURE_ALERT = 'oil.pressure.alert' + OUT_OF_PARK_POSITION_CHARGE_INTERRUPTION = 'out.of.park.position.charge.interruption' + PLUG_CONNECTION_ISSUE = 'plug.connection.issue' + PLUG_CONNECTION_SUCCESS = 'plug.connection.success' + PLUG_UNLOCKING = 'plug.unlocking' + PREREMINDER_ALERT_DEFAULT = 'prereminder.alert.default' + PRIVACY_MODE_OFF = 'privacy.mode.off' + PRIVACY_MODE_ON = 'privacy.mode.on' + PROGRAMMED_CHARGE_INTERRUPTION = 'programmed.charge.interruption' + PROHIBITION_BATTERY_RENTAL = 'prohibition.battery.rental' + PWT_START_IMPOSSIBLE = 'pwt.start.impossible' + REMOTE_LEFT_TIME_CYCLE = 'remote.left.time.cycle' + REMOTE_START_CUSTOMER = 'remote.start.customer' + REMOTE_START_ENGINE = 'remote.start.engine' + REMOTE_START_NORMAL_ONLY = 'remote.start.normal.only' + REMOTE_START_PHONE_ERROR = 'remote.start.phone.error' + REMOTE_START_UNAVAILABLE = 'remote.start.unavailable' + REMOTE_START_WAIT_PRESOAK = 'remote.start.wait.presoak' + RENAULT_RESET_FACTORY = 'renault.reset.factory' + RGDC_CHARGE_COMPLETE = 'rgdc.charge.complete' + RGDC_CHARGE_ERROR = 'rgdc.charge.error' + RGDC_CHARGE_ON = 'rgdc.charge.on' + RGDC_CHARGE_STATUS = 'rgdc.charge.status' + RGDC_LOW_BATTERY_ALERT = 'rgdc.low.battery.alert' + RGDC_LOW_BATTERY_REMINDER = 'rgdc.low.battery.reminder' + SERV_WARNING_ALERT = 'serv.warning.alert' + SPEED_INFRINGEMENT = 'speed.infringement' + SPEED_RECOVERY = 'speed.recovery' + SRP_PINCODE_ACKNOWLEDGEMENT = 'srp.pincode.acknowledgement' + SRP_PINCODE_DELETION = 'srp.pincode.deletion' + SRP_PINCODE_STATUS = 'srp.pincode.status' + SRP_SALT_REQUEST = 'srp.salt.request' + START_DRIVING_CHARGE_INTERRUPTION = 'start.driving.charge.interruption' + START_IN_PROGRESS = 'start.in.progress' + STATUS_OIL_PRESSURE_SWITCH_CLOSED = 'status.oil.pressure.switch.closed' + STATUS_OIL_PRESSURE_SWITCH_OPEN = 'status.oil.pressure.switch.open' + STOLEN_VEHICLE_TRACKING = 'stolen.vehicle.tracking' + STOLEN_VEHICLE_TRACKING_BLOCKING = 'stolen.vehicle.tracking.blocking' + STOP_WARNING_ALERT = 'stop.warning.alert' + SVT_SERVICE_ACTIVATION = 'svt.service.activation' + UNPLUG_CHARGE = 'unplug.charge' + WAITING_PLANNED_CHARGE = 'waiting.planned.charge' + WHEEL_ALERT = 'wheel.alert' + ZONE_INFRINGEMENT = 'zone.infringement' + ZONE_RECOVERY = 'zone.recovery' + + +class NotificationPriority(enum.Enum): + + NONE = None + P0 = 0 + P1 = 1 + P2 = 2 + P3 = 3 + + +class NotificationRuleStatus(enum.Enum): + ACTIVATED = 'ACTIVATED' + ACTIVATION_IN_PROGRESS = 'STATUS_ACTIVATION_IN_PROGRESS' + DELETION_IN_PROGRESS = 'STATUS_DELETION_IN_PROGRESS' diff --git a/custom_components/nissan_connect/switch.py b/custom_components/nissan_connect/switch.py deleted file mode 100644 index 3f4543a..0000000 --- a/custom_components/nissan_connect/switch.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Support for Kamereon switches.""" -import logging - -from homeassistant.helpers.entity import ToggleEntity - -from . import DATA_KEY, KamereonEntity - -_LOGGER = logging.getLogger(__name__) - - -async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): - """Set up a Kamereon car switch.""" - if discovery_info is None: - return - #async_add_entities([KamereonSwitch(discovery_info)]) - - -class KamereonSwitch(KamereonEntity, ToggleEntity): - """Representation of a Kamereon car switch.""" - - @property - def _switch(self): - return NotImplemented - - @property - def is_on(self): - """Return true if switch is on.""" - return self._state - - async def async_turn_on(self, **kwargs): - """Turn the switch on.""" - await self.instrument.turn_on() - - async def async_turn_off(self, **kwargs): - """Turn the switch off.""" - await self.instrument.turn_off() \ No newline at end of file