Skip to content

Commit

Permalink
✨ v2.6.0 (#148)
Browse files Browse the repository at this point in the history
* ✨ v2.6.0

Signed-off-by: Ludy87 <Ludy87@users.noreply.github.com>

* Update README.md

* Update coordinator.py

* Update services.py

* Update coordinator.py

* Update config_flow.py

* Update switch.py

* Update services.py

* Update README.md

* Update services.py

* Update services.py

* Update hacs.json

* Update hacs.json

* Update coordinator.py

* Update manifest.json

* Update services.py

---------

Signed-off-by: Ludy87 <Ludy87@users.noreply.github.com>
  • Loading branch information
Ludy87 authored Jan 29, 2023
1 parent 106f49c commit 815ad53
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 63 deletions.
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Xplora® Watch Version 2 integration for Home Assistant
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=for-the-badge&logo=appveyor)](https://github.com/psf/black)

[![Validate with hassfest and HACS](https://github.com/Ludy87/xplora_watch/actions/workflows/hassfest.yaml/badge.svg)](https://github.com/Ludy87/xplora_watch/actions/workflows/hassfest.yaml)
![Code Grade](https://api.codiga.io/project/35408/status/svg)
![Code Quality Score](https://api.codiga.io/project/35408/score/svg)

[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ludy87)

Expand All @@ -32,8 +34,9 @@ Xplora® Watch Version 2 integration for Home Assistant
| Watch silent(s) | Switch |
| Watch alarm(s) | Switch |
| [Send Message](https://github.com/Ludy87/xplora_watch#send-message) | Notify |
| [Send Message](https://github.com/Ludy87/xplora_watch#send-message-via-service-v203) | Service |
| [Send Message Service](https://github.com/Ludy87/xplora_watch#send-message-via-service-v203) | Service |
| [Read Messages from Account](https://github.com/Ludy87/xplora_watch#read-messages-from-account-v240) | Service |
| [Delete Messages from App](https://github.com/Ludy87/xplora_watch#delete-messages-from-app-v260) | Service |
| [Manually update](https://github.com/Ludy87/xplora_watch#manually-update-v208--v209) | Service |
| turn off Watch | Service |
| Watch Tracking | Device Tracker |
Expand Down Expand Up @@ -70,12 +73,45 @@ Xplora® should now appear as a card under the HA Integrations page with "Config

---

## Delete Messages from App (v2.6.0)

- new service added - delete only app message
- chats: add ```delete_flag``` `1` = message is deleted
- updated [Markdown Card Sample](https://raw.githubusercontent.com/Ludy87/xplora_watch/main/samples/markdown-card-read-messages.md)
- add Emoji
- M1001 = "😄"
- M1002 = "😏"
- M1003 = "😘"
- M1004 = "😅"
- M1005 = "😂"
- M1006 = "😭"
- M1007 = "😍"
- M1008 = "😎"
- M1009 = "😜"
- M1010 = "😳"
- M1011 = "🥱"
- M1012 = "👏"
- M1013 = "😡"
- M1014 = "👍"
- M1015 = "😏"
- M1016 = "😓"
- M1017 = "🍧"
- M1018 = "😮"
- M1019 = "M1019"
- M1020 = "🎁"
- M1021 = "M1021"
- M1022 = "☺️"
- M1023 = "M1023"
- M1024 = "🌹"

---

## Read Messages from Account (v2.4.0)

- A new (message) sensor has been added, default: disabled
- new service added, (message) sensor will be updated
- change Number of Messages option find in "Configure"
- [Markdown Card Sample](https://raw.githubusercontent.com/Ludy87/xplora_watch/main/samples/markdown-card-read-messages.md)
- [Markdown Card Sample](https://raw.githubusercontent.com/Ludy87/xplora_watch/main/samples/markdown-card-read-messages.md) (updated v2.6.0)
- [Automation Sample](https://raw.githubusercontent.com/Ludy87/xplora_watch/main/samples/automation-read-messages.yaml)

![markdown sample](https://raw.githubusercontent.com/Ludy87/xplora_watch/main/images/markdown_sample.png)
Expand Down
6 changes: 4 additions & 2 deletions custom_components/xplora_watch/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
CONF_MESSAGE,
CONF_OPENCAGE_APIKEY,
CONF_PHONENUMBER,
CONF_REMOVE_MESSAGE,
CONF_SIGNIN_TYP,
CONF_TIMEZONE,
CONF_TYPES,
Expand Down Expand Up @@ -159,7 +160,7 @@ async def async_step_user_phone(self, user_input: dict[str, Any] | None = None)

unique_id = f"{user_input[CONF_PHONENUMBER]}"

self.entry = await self.async_set_unique_id(unique_id)
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()

info = None
Expand Down Expand Up @@ -189,7 +190,7 @@ async def async_step_user_email(self, user_input: dict[str, Any] | None = None)

unique_id = f"{user_input[CONF_EMAIL]}"

self.entry = await self.async_set_unique_id(unique_id)
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()

info = None
Expand Down Expand Up @@ -278,6 +279,7 @@ async def async_step_init(self, user_input: dict[str, Any] | None = None) -> Flo
SENSORS.get(language, DEFAULT_LANGUAGE)
),
vol.Required(CONF_MESSAGE, default=_options.get(CONF_MESSAGE, 10)): cv.positive_int,
vol.Required(CONF_REMOVE_MESSAGE, default=_options.get(CONF_REMOVE_MESSAGE, False)): cv.boolean,
}
)

Expand Down
46 changes: 46 additions & 0 deletions custom_components/xplora_watch/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
URL_OPENSTREETMAP = "https://nominatim.openstreetmap.org/reverse?lat={}&lon={}&format=jsonv2&accept-language={}"

ATTR_SERVICE_MSG: Final = "message"
ATTR_SERVICE_MSGID: Final = "message_id"
ATTR_SERVICE_SEE: Final = "see"
ATTR_SERVICE_DELETE_MSG: Final = "delete_message_from_app"
ATTR_SERVICE_READ_MSG: Final = "read_message"
ATTR_SERVICE_SEND_MSG: Final = "send_message"
ATTR_SERVICE_SHUTDOWN: Final = "shutdown"
Expand Down Expand Up @@ -41,6 +43,7 @@
CONF_MESSAGE: Final = "message"
CONF_OPENCAGE_APIKEY: Final = "opencage_apikey"
CONF_PHONENUMBER: Final = "phonenumber"
CONF_REMOVE_MESSAGE: Final = "remove_message"
CONF_SIGNIN_TYP: Final = "signin_typ"
CONF_TIMEZONE: Final = "timezone"
CONF_TYPES: Final = "types"
Expand Down Expand Up @@ -274,3 +277,46 @@
- all
""",
}

STR_DELETE_MESSAGE_FROM_APP: Final[dict[str, str]] = {
"en": """
delete_message_from_app:
name: Remove Message
description: Delete message in the Xplora® app
fields:
message_id:
name: Message ID
description: Enter the message ID to be deleted in the app, does not affect the messages in the watch.
required: true
selector:
text:
target:
name: Uhr(en)
description: Select your clock to turn off.
required: true
selector:
select:
options:
- all
""",
"de": """
delete_message_from_app:
name: Nachricht löschen
description: Nachricht in der Xplora® App löschen
fields:
message_id:
name: Nachrichten ID
description: Trage die Nachrichten ID ein, die in der App gelöscht werden soll, hat keinen einfluß auf die Nachrichten in der Uhr.
required: true
selector:
text:
target:
name: Uhr(en)
description: W\u00e4hle deine Uhr aus, die ausgeschaltet werden soll.
required: true
selector:
select:
options:
- all
""",
}
60 changes: 37 additions & 23 deletions custom_components/xplora_watch/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

import aiohttp
from pyxplora_api import pyxplora_api_async as PXA
from pyxplora_api.model import ChatsNew

from homeassistant.components.device_tracker.const import ATTR_BATTERY, ATTR_LOCATION_NAME
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, CONF_SCAN_INTERVAL
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import (
Expand All @@ -28,13 +29,16 @@
CONF_MESSAGE,
CONF_OPENCAGE_APIKEY,
CONF_PHONENUMBER,
CONF_REMOVE_MESSAGE,
CONF_TIMEZONE,
CONF_USERLANG,
CONF_WATCHES,
DEFAULT_LANGUAGE,
DEFAULT_SCAN_INTERVAL,
DOMAIN,
MAPS,
SENSOR_MESSAGE,
SENSOR_XCOIN,
URL_OPENSTREETMAP,
)
from .geocoder import OpenCageGeocodeUA
Expand All @@ -51,11 +55,12 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
self._entry = entry
self.opencage_apikey = entry.options.get(CONF_OPENCAGE_APIKEY, "")
self.maps = entry.options.get(CONF_MAPS, MAPS[0])
self._xcoin = 0
super().__init__(
hass,
_LOGGER,
name=f'{DOMAIN}-{entry.data[CONF_PHONENUMBER][5:] if CONF_EMAIL not in entry.data else ""}',
update_method=self._async_update_watch_data,
update_method=self.update_watch_data,
update_interval=timedelta(seconds=entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)),
)

Expand All @@ -72,34 +77,43 @@ async def init(self) -> PXA.PyXploraApi:
await self.controller.init(forceLogin=True)
return self.controller

async def _async_update_watch_data(self, targets: list[str] | None = None) -> dict[str, Any]:
"""Fetch data from Xplora®."""
async def update_watch_data(self, targets: list[str] = None):
"""Fetch data from Xplora."""
await self.init()
_LOGGER.debug("pyxplora_api Lib version: %s", self.controller.version())
self.watch_entry: dict[str, Any] = {}
_LOGGER.debug("pyxplora_api lib version: %s", self.controller.version())

# Initialize the watch entry data
self.watch_entry = {}
if self.data:
self.watch_entry.update(self.data)

# Get the list of watch UUIDs
if targets:
wuids = await self.controller.setDevices(targets)
else:
wuids = self._entry.options.get(CONF_WATCHES, await self.controller.setDevices())
for wuid in wuids:
_LOGGER.debug("Fetch data from Xplora®: %s", wuid[25:])
device: dict[str, Any] = self.controller.getDevice(wuid=wuid)

chats: dict[str, Any] = (
await self.controller.getWatchChatsRaw(wuid, limit=self._entry.options.get(CONF_MESSAGE, 10))
).get("chatsNew", {"list: []"})
# Get the message limit and remove message option
message_limit = self._entry.options.get(CONF_MESSAGE, 10)
remove_message = self._entry.options.get(CONF_REMOVE_MESSAGE, False)

# Loop through the list of watches and fetch data
for wuid in wuids:
_LOGGER.debug("Fetch data from Xplora: %s", wuid[25:])
device = self.controller.getDevice(wuid=wuid)
res_chats = await self.controller.getWatchChatsRaw(wuid, limit=message_limit, show_del_msg=remove_message)
chats = ChatsNew.from_dict(res_chats).to_dict()
watch_location = await self.controller.loadWatchLocation(wuid)

watchLocate: dict[str, Any] = device.get("loadWatchLocation", {})
# Update the watch data
self.unreadMsg = await self.controller.getWatchUnReadChatMsgCount(wuid)
self.battery = watchLocate.get("watch_battery", -1)
self.isCharging = watchLocate.get("watch_charging", False)
self.lat = float(watchLocate.get(ATTR_TRACKER_LAT, 0.0))
self.lng = float(watchLocate.get(ATTR_TRACKER_LNG, 0.0))
self.poi = watchLocate.get(ATTR_TRACKER_POI, "")
self.location_accuracy = watchLocate.get(ATTR_TRACKER_RAD, -1)
self.locateType = watchLocate.get("locateType", PXA.LocationType.UNKNOWN.value)
self.battery = watch_location.get("watch_battery", -1)
self.isCharging = watch_location.get("watch_charging", False)
self.lat = float(watch_location.get(ATTR_TRACKER_LAT, 0.0))
self.lng = float(watch_location.get(ATTR_TRACKER_LNG, 0.0))
self.poi = watch_location.get(ATTR_TRACKER_POI, "")
self.location_accuracy = watch_location.get(ATTR_TRACKER_RAD, -1)
self.locateType = watch_location.get("locateType", PXA.LocationType.UNKNOWN.value)
self.lastTrackTime = device.get("lastTrackTime", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

self.isSafezone = False if device.get("isInSafeZone", False) else True
Expand All @@ -122,7 +136,7 @@ async def _async_update_watch_data(self, targets: list[str] | None = None) -> di
self.entity_picture = device.get("getWatchUserIcons", "")

self._step_day = device.get("getWatchUserSteps", {}).get("day")
self._xcoin = device.get("getWatchUserXcoins", Any)
self._xcoin = device.get("getWatchUserXcoins", 0)
licence = None
if self.maps == MAPS[1]:
async with OpenCageGeocodeUA(self.opencage_apikey) as geocoder:
Expand Down Expand Up @@ -155,7 +169,7 @@ async def _async_update_watch_data(self, targets: list[str] | None = None) -> di
"alarm": self.alarm,
"silent": self.silent,
"step_day": self._step_day,
"xcoin": self._xcoin,
SENSOR_XCOIN: self._xcoin,
ATTR_TRACKER_LAT: self.lat if self.isOnline else None,
ATTR_TRACKER_LNG: self.lng if self.isOnline else None,
ATTR_TRACKER_POI: self.poi if self.poi else None,
Expand All @@ -169,7 +183,7 @@ async def _async_update_watch_data(self, targets: list[str] | None = None) -> di
"locateType": self.locateType,
"lastTrackTime": self.lastTrackTime,
ATTR_TRACKER_LICENCE: licence,
"message": chats,
SENSOR_MESSAGE: chats,
}
}
)
Expand Down
5 changes: 5 additions & 0 deletions custom_components/xplora_watch/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
CONF_LANGUAGE,
DEFAULT_LANGUAGE,
HOME,
STR_DELETE_MESSAGE_FROM_APP,
STR_READ_MESSAGE_SERVICE,
STR_SEE_SERVICE,
STR_SEND_MESSAGE_SERVICE,
Expand Down Expand Up @@ -61,5 +62,9 @@ def create_service_yaml_file(hass: HomeAssistant, entry: ConfigEntry, watches: l
for watch in watches:
f.write(f' - "{watch}"\n')

f.write(STR_DELETE_MESSAGE_FROM_APP.get(language, DEFAULT_LANGUAGE))
for watch in watches:
f.write(f' - "{watch}"\n')

except IOError:
_LOGGER.exception("Error writing service definition to path '%s'", path)
4 changes: 2 additions & 2 deletions custom_components/xplora_watch/manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"domain": "xplora_watch",
"name": "Xplora® Watch",
"version": "v2.5.8",
"version": "v2.6.0",
"config_flow": true,
"documentation": "https://github.com/Ludy87/xplora_watch/tree/main",
"issue_tracker": "https://github.com/Ludy87/xplora_watch/issues",
"dependencies": [],
"requirements": [
"pyxplora_api==2.4.9",
"pyxplora_api==2.5.5",
"geopy==2.2.0",
"dataclasses-json"
],
Expand Down
2 changes: 2 additions & 0 deletions custom_components/xplora_watch/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ def native_value(self) -> StateType:
float(self.coordinator.data[self.watch_uid][ATTR_TRACKER_LNG]),
)
return get_location_distance_meter(self.hass, lat_lng)
else:
return -1
return None

@property
Expand Down
Loading

0 comments on commit 815ad53

Please sign in to comment.