Skip to content

Commit

Permalink
Merge pull request #226 from sh00t2kill/develop
Browse files Browse the repository at this point in the history
v1.0.18
  • Loading branch information
elad-bar authored Jul 25, 2024
2 parents 26ce1d4 + a71b235 commit 8aab519
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 256 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ venv/

__test__.py
tokens.json
config.json
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## v1.0.18

- Change interval of calling API to once an hour (instead of a minute)
- Change interval of calling publishing websocket message to every 5 minutes (instead of 30 seconds)
- Add status of connectivity - Expired Token to reset all tokens once HTTP Error 401 is being returned by the API
- Remove duplicate names of constants and duplicate storage of parameters
- Validate AWS token is being generated as valid base64 token instead retry mechanism of get token API (another deduction of calls to API from 5 to single)
- Align test API to the same standard of configuration storage of HA
- Clean entity creation / update log (no actions within logged data)

## v1.0.17

- Optimized login request and store tokens to avoid abuse of the login API
Expand Down
8 changes: 6 additions & 2 deletions custom_components/mydolphin_plus/common/base_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from ..managers.config_manager import ConfigManager
from ..managers.coordinator import MyDolphinPlusCoordinator
from .consts import DATA_ROBOT_FAMILY, DOMAIN
from .consts import ATTR_ACTIONS, DATA_ROBOT_FAMILY, DOMAIN
from .entity_descriptions import MyDolphinPlusEntityDescription, get_entity_descriptions
from .robot_family import RobotFamily

Expand Down Expand Up @@ -124,7 +124,11 @@ def _handle_coordinator_update(self) -> None:
new_data = self._local_coordinator.get_data(self.entity_description)

if self._data != new_data:
_LOGGER.debug(f"Data for {self.unique_id}: {new_data}")
data_for_log = {
key: new_data[key] for key in new_data if key != ATTR_ACTIONS
}

_LOGGER.debug(f"Data for {self.unique_id}: {data_for_log}")

self.update_component(new_data)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ConnectivityStatus(StrEnum):
DISCONNECTED = "Disconnected by the system"
API_NOT_FOUND = "API Not found"
INVALID_ACCOUNT = "Invalid account"
EXPIRED_TOKEN = "Expired Token"

@staticmethod
def get_log_level(status: StrEnum) -> int:
Expand All @@ -23,7 +24,10 @@ def get_log_level(status: StrEnum) -> int:
ConnectivityStatus.TEMPORARY_CONNECTED,
]:
return logging.INFO
elif status in [ConnectivityStatus.NOT_CONNECTED]:
elif status in [
ConnectivityStatus.NOT_CONNECTED,
ConnectivityStatus.EXPIRED_TOKEN,
]:
return logging.WARNING
else:
return logging.ERROR
Expand Down
29 changes: 17 additions & 12 deletions custom_components/mydolphin_plus/common/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,10 @@
DEFAULT_TIME_ZONE_NAME = "UTC"
DEFAULT_TIME_PART = 255

UPDATE_API_INTERVAL = timedelta(seconds=60)
UPDATE_API_INTERVAL = timedelta(hours=1)
UPDATE_WS_INTERVAL = timedelta(minutes=5)
UPDATE_ENTITIES_INTERVAL = timedelta(seconds=5)
API_RECONNECT_INTERVAL = timedelta(seconds=30)
API_RECONNECT_INTERVAL = timedelta(minutes=1)
WS_RECONNECT_INTERVAL = timedelta(minutes=1)

WS_LAST_UPDATE = "last-update"
Expand All @@ -141,6 +142,8 @@
API_RESPONSE_ALERT = "Alert"
API_RESPONSE_STATUS_FAILURE = "0"
API_RESPONSE_STATUS_SUCCESS = "1"
API_RESPONSE_STATUS_INVALID_REQUEST = "-1"
API_RESPONSE_STATUS_INVALID_MOTOR_UNIT_SERIAL = "-20"
API_RESPONSE_UNIT_SERIAL_NUMBER = "eSERNUM"

API_RESPONSE_IS_EMAIL_EXISTS = "isEmailExists"
Expand All @@ -149,10 +152,6 @@
API_RESPONSE_DATA_ACCESS_KEY_ID = "AccessKeyId"
API_RESPONSE_DATA_SECRET_ACCESS_KEY = "SecretAccessKey"

API_DATA_MOTOR_UNIT_SERIAL = "motor_unit_serial"
API_DATA_SERIAL_NUMBER = "serial_number"
API_DATA_LOGIN_TOKEN = "login_token"

API_TOKEN_FIELDS = [
API_RESPONSE_DATA_TOKEN,
API_RESPONSE_DATA_ACCESS_KEY_ID,
Expand All @@ -172,8 +171,9 @@
LOGIN_HEADERS = {
"appkey": "346BDE92-53D1-4829-8A2E-B496014B586C",
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
"integration-version": "1.0.17",
"integration-version": "1.0.18",
}

CA_FILE_NAME = "AmazonRootCA.pem"

TOPIC_SHADOW = "$aws/things/{}/shadow"
Expand Down Expand Up @@ -288,7 +288,7 @@

STORAGE_DATA_KEY = "key"
STORAGE_DATA_LOCATING = "locating"
STORAGE_DATA_AWS_TOKEN_ENCRYPTED_KEY = "aws-token-encrypted-key"
STORAGE_DATA_AWS_TOKEN = "aws-token"
STORAGE_DATA_API_TOKEN = "api-token"
STORAGE_DATA_SERIAL_NUMBER = "serial-number"
STORAGE_DATA_MOTOR_UNIT_SERIAL = "motor-unit-serial"
Expand Down Expand Up @@ -330,15 +330,20 @@

EVENT_ERROR = f"{DOMAIN}_error"

TOKEN_PARAMS = [
STORAGE_DATA_AWS_TOKEN,
STORAGE_DATA_API_TOKEN,
STORAGE_DATA_SERIAL_NUMBER,
STORAGE_DATA_MOTOR_UNIT_SERIAL,
]

TO_REDACT = [
STORAGE_DATA_AWS_TOKEN_ENCRYPTED_KEY,
API_DATA_SERIAL_NUMBER,
API_DATA_LOGIN_TOKEN,
API_DATA_MOTOR_UNIT_SERIAL,
API_RESPONSE_DATA_TOKEN,
API_RESPONSE_DATA_ACCESS_KEY_ID,
API_RESPONSE_DATA_SECRET_ACCESS_KEY,
DYNAMIC_CONTENT_SERIAL_NUMBER,
CONF_USERNAME,
CONF_PASSWORD,
]

TO_REDACT.extend(TOKEN_PARAMS)
33 changes: 10 additions & 23 deletions custom_components/mydolphin_plus/managers/aws_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
from ..common.connection_callbacks import ConnectionCallbacks
from ..common.connectivity_status import IGNORED_TRANSITIONS, ConnectivityStatus
from ..common.consts import (
API_DATA_MOTOR_UNIT_SERIAL,
API_DATA_SERIAL_NUMBER,
API_RESPONSE_DATA_ACCESS_KEY_ID,
API_RESPONSE_DATA_SECRET_ACCESS_KEY,
API_RESPONSE_DATA_TOKEN,
Expand Down Expand Up @@ -74,7 +72,6 @@
SIGNAL_AWS_CLIENT_STATUS,
TOPIC_CALLBACK_ACCEPTED,
TOPIC_CALLBACK_REJECTED,
UPDATE_API_INTERVAL,
WS_DATA_DIFF,
WS_DATA_TIMESTAMP,
WS_DATA_VERSION,
Expand Down Expand Up @@ -195,9 +192,7 @@ async def initialize(self):
f"AWS IAM Credentials, Key: {aws_key}, Secret: {aws_secret}, Token: {aws_token}"
)

motor_unit_serial = self._api_data.get(API_DATA_MOTOR_UNIT_SERIAL)

self._topic_data = TopicData(motor_unit_serial)
self._topic_data = TopicData(self._config_manager.motor_unit_serial)

ca_content = await self._get_certificate()

Expand Down Expand Up @@ -303,29 +298,21 @@ async def update_api_data(self, api_data: dict):
self._robot_family = RobotFamily.from_string(robot_family_str)

async def update(self):
if self._status == ConnectivityStatus.CONNECTED:
_LOGGER.debug("Connected. Refresh details")
await self._refresh_details()

async def _refresh_details(self, forced: bool = False):
try:
now = datetime.now().timestamp()
last_update = self.data.get(WS_LAST_UPDATE, 0)
if self._status == ConnectivityStatus.CONNECTED:
_LOGGER.debug("Connected. Refresh details")

diff_seconds = int(now) - last_update
now = datetime.now().timestamp()

if forced or diff_seconds >= UPDATE_API_INTERVAL.total_seconds():
self.data[WS_LAST_UPDATE] = int(now)

self._publish(self._topic_data.get, None)
self._publish(self._topic_data.get)

except Exception as ex:
exc_type, exc_obj, tb = sys.exc_info()
line_number = tb.tb_lineno

_LOGGER.error(
f"Failed to refresh MyDolphin Plus WS data, error: {ex}, line: {line_number}"
)
_LOGGER.error(f"Failed to update WS data, error: {ex}, line: {line_number}")

def _on_connection_success(self, connection, callback_data):
if isinstance(callback_data, mqtt.OnConnectionSuccessData):
Expand Down Expand Up @@ -394,7 +381,7 @@ def _message_callback(self, topic, payload, dup, qos, retain, **kwargs):
has_message = len(message_payload) <= 0
payload_data = {} if has_message else json.loads(message_payload)

motor_unit_serial = self._api_data.get(API_DATA_SERIAL_NUMBER)
motor_unit_serial = self._config_manager.motor_unit_serial
_LOGGER.debug(
f"Message received for device {motor_unit_serial}, Topic: {topic}"
)
Expand Down Expand Up @@ -479,7 +466,7 @@ def _send_dynamic_command(self, description: str, payload: dict | None):

self._publish(self._topic_data.dynamic, payload)

def _publish(self, topic: str, data: dict | None):
def _publish(self, topic: str, data: dict | None = None):
if data is None:
data = {}

Expand Down Expand Up @@ -583,8 +570,8 @@ def exit_navigation(self):
self._send_dynamic_command(DYNAMIC_DESCRIPTION_JOYSTICK, request_data)

def _read_temperature_and_in_water_details(self):
motor_unit_serial = self._api_data.get(API_DATA_SERIAL_NUMBER)
serial_number = self._api_data.get(API_DATA_SERIAL_NUMBER)
motor_unit_serial = self._config_manager.motor_unit_serial
serial_number = self._config_manager.serial_number

request_data = {
DYNAMIC_CONTENT_SERIAL_NUMBER: serial_number,
Expand Down
Loading

0 comments on commit 8aab519

Please sign in to comment.