mirror of
https://github.com/natekspencer/hacs-oasis_mini.git
synced 2025-11-08 05:03:52 -05:00
Compare commits
12 Commits
b5b3e691e2
...
1.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21fd8a63ba | ||
|
|
552339665f | ||
|
|
85449a5363 | ||
|
|
d2bc89bdd7 | ||
|
|
06008e8f4c | ||
|
|
9fdfd8129f | ||
|
|
f9237927d9 | ||
|
|
dcd8db52f5 | ||
|
|
86cf060af0 | ||
|
|
d7a803abc7 | ||
|
|
a1bb4c78fb | ||
|
|
50f7b270f2 |
@@ -61,6 +61,11 @@ DESCRIPTORS = (
|
||||
translation_key="random_track",
|
||||
press_fn=play_random_track,
|
||||
),
|
||||
OasisMiniButtonEntityDescription(
|
||||
key="sleep",
|
||||
translation_key="sleep",
|
||||
press_fn=lambda device: device.async_sleep(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from urllib.parse import urljoin
|
||||
from aiohttp import ClientResponseError, ClientSession
|
||||
|
||||
from .const import TRACKS
|
||||
from .utils import _bit_to_bool, decrypt_svg_content
|
||||
from .utils import _bit_to_bool, _parse_int, decrypt_svg_content
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -20,9 +20,11 @@ STATUS_CODE_MAP = {
|
||||
3: "centering",
|
||||
4: "playing",
|
||||
5: "paused",
|
||||
6: "sleeping",
|
||||
9: "error",
|
||||
11: "updating",
|
||||
13: "downloading",
|
||||
14: "busy",
|
||||
15: "live",
|
||||
}
|
||||
|
||||
@@ -51,12 +53,39 @@ LED_EFFECTS: Final[dict[str, str]] = {
|
||||
"12": "Follow Rainbow",
|
||||
"13": "Chasing Comet",
|
||||
"14": "Gradient Follow",
|
||||
"15": "Cumulative Fill",
|
||||
"16": "Multi Comets A",
|
||||
"17": "Rainbow Chaser",
|
||||
"18": "Twinkle Lights",
|
||||
"19": "Tennis Game",
|
||||
"20": "Breathing Exercise 4-7-8",
|
||||
"21": "Cylon Scanner",
|
||||
"22": "Palette Mode",
|
||||
"23": "Aurora Flow",
|
||||
"24": "Colorful Drops",
|
||||
"25": "Color Snake",
|
||||
"26": "Flickering Candles",
|
||||
"27": "Digital Rain",
|
||||
"28": "Center Explosion",
|
||||
"29": "Rainbow Plasma",
|
||||
"30": "Comet Race",
|
||||
"31": "Color Waves",
|
||||
"32": "Meteor Storm",
|
||||
"33": "Firefly Flicker",
|
||||
"34": "Ripple",
|
||||
"35": "Jelly Bean",
|
||||
"36": "Forest Rain",
|
||||
"37": "Multi Comets",
|
||||
"38": "Multi Comets with Background",
|
||||
"39": "Rainbow Fill",
|
||||
"40": "White Red Comet",
|
||||
"41": "Color Comets",
|
||||
}
|
||||
|
||||
CLOUD_BASE_URL = "https://app.grounded.so"
|
||||
|
||||
BALL_SPEED_MAX: Final = 1000
|
||||
BALL_SPEED_MIN: Final = 200
|
||||
BALL_SPEED_MAX: Final = 400
|
||||
BALL_SPEED_MIN: Final = 100
|
||||
LED_SPEED_MAX: Final = 90
|
||||
LED_SPEED_MIN: Final = -90
|
||||
|
||||
@@ -210,25 +239,29 @@ class OasisMini:
|
||||
raw_status = await self._async_get(params={"GETSTATUS": ""})
|
||||
_LOGGER.debug("Status: %s", raw_status)
|
||||
values = raw_status.split(";")
|
||||
playlist = [int(track) for track in values[3].split(",") if track]
|
||||
playlist = [_parse_int(track) for track in values[3].split(",") if track]
|
||||
shift = len(values) - 18 if len(values) > 17 else 0
|
||||
status = {
|
||||
"status_code": int(values[0]), # see status code map
|
||||
"error": int(values[1]), # noqa: E501; error, 0 = none, and 10 = ?, 18 = can't download?
|
||||
"ball_speed": int(values[2]), # 200 - 1000
|
||||
"status_code": _parse_int(values[0]), # see status code map
|
||||
"error": _parse_int(values[1]), # noqa: E501; error, 0 = none, and 10 = ?, 18 = can't download?
|
||||
"ball_speed": _parse_int(values[2]), # 200 - 1000
|
||||
"playlist": playlist,
|
||||
"playlist_index": min(int(values[4]), len(playlist)), # index of above
|
||||
"progress": int(values[5]), # 0 - max svg path
|
||||
"playlist_index": min(_parse_int(values[4]), len(playlist)), # noqa: E501; index of above
|
||||
"progress": _parse_int(values[5]), # 0 - max svg path
|
||||
"led_effect": values[6], # led effect (code lookup)
|
||||
"led_color_id": values[7], # led color id?
|
||||
"led_speed": int(values[8]), # -90 - 90
|
||||
"brightness": int(values[9]) if values[10] else 0, # noqa: E501; 0 - 200 in app, but seems to be 0 (off) to 304 (max), then repeats
|
||||
"color": values[10] or None, # hex color code
|
||||
"busy": _bit_to_bool(values[11]), # noqa: E501; device is busy (downloading track, centering, software update)?
|
||||
"download_progress": int(values[12]),
|
||||
"max_brightness": int(values[13]),
|
||||
"wifi_connected": _bit_to_bool(values[14]),
|
||||
"repeat_playlist": _bit_to_bool(values[15]),
|
||||
"autoplay": AUTOPLAY_MAP.get(value := values[16], value),
|
||||
"led_speed": _parse_int(values[8]), # -90 - 90
|
||||
"brightness": _parse_int(values[9]), # noqa: E501; 0 - 200 in app, but seems to be 0 (off) to 304 (max), then repeats
|
||||
"color": values[10] if "#" in values[10] else None, # hex color code
|
||||
"busy": _bit_to_bool(values[11 + shift]), # noqa: E501; device is busy (downloading track, centering, software update)?
|
||||
"download_progress": _parse_int(values[12 + shift]),
|
||||
"max_brightness": _parse_int(values[13 + shift]),
|
||||
"wifi_connected": _bit_to_bool(values[14 + shift]),
|
||||
"repeat_playlist": _bit_to_bool(values[15 + shift]),
|
||||
"autoplay": AUTOPLAY_MAP.get(value := values[16 + shift], value),
|
||||
"autoclean": _bit_to_bool(values[17 + shift])
|
||||
if len(values) > 17
|
||||
else False,
|
||||
}
|
||||
for key, value in status.items():
|
||||
if (old_value := getattr(self, key, None)) != value:
|
||||
@@ -327,6 +360,10 @@ class OasisMini:
|
||||
"""Set repeat playlist."""
|
||||
await self._async_command(params={"WRIREPEATJOB": 1 if repeat else 0})
|
||||
|
||||
async def async_sleep(self) -> None:
|
||||
"""Send sleep command."""
|
||||
await self._async_command(params={"CMDSLEEP": ""})
|
||||
|
||||
async def async_stop(self) -> None:
|
||||
"""Send stop command."""
|
||||
await self._async_command(params={"CMDSTOP": ""})
|
||||
|
||||
@@ -269,6 +269,14 @@
|
||||
"1": 18767
|
||||
}
|
||||
},
|
||||
"8503": {
|
||||
"id": 8503,
|
||||
"name": "Angry Badger",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/07/e322d3ade30f0a0e9af497a13257efab.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"8341": {
|
||||
"id": 8341,
|
||||
"name": "Angry Cat",
|
||||
@@ -749,6 +757,14 @@
|
||||
"1": 3920
|
||||
}
|
||||
},
|
||||
"8485": {
|
||||
"id": 8485,
|
||||
"name": "Bodhi tree",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/637f117735a86aa56a9eb590d7d805ac.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"7915": {
|
||||
"id": 7915,
|
||||
"name": "Bonsai tree",
|
||||
@@ -759,6 +775,14 @@
|
||||
"1": 55010
|
||||
}
|
||||
},
|
||||
"8511": {
|
||||
"id": 8511,
|
||||
"name": "Botanic Spiral",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/07/3a2c85f1216662881ae2ee783382734f.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"56": {
|
||||
"id": 56,
|
||||
"name": "Branch",
|
||||
@@ -1040,6 +1064,14 @@
|
||||
"1": 28146
|
||||
}
|
||||
},
|
||||
"8441": {
|
||||
"id": 8441,
|
||||
"name": "Cherry Blossom Bonsai",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/f1a6e7624e05a330c1d439001f3f09f5.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"7478": {
|
||||
"id": 7478,
|
||||
"name": "ChevronWipe OO",
|
||||
@@ -1273,6 +1305,14 @@
|
||||
},
|
||||
"updated_at": "2024-08-04T16:01:33.000000Z"
|
||||
},
|
||||
"8586": {
|
||||
"id": 8586,
|
||||
"name": "Clover Star",
|
||||
"author": "Walter Melanson",
|
||||
"image": "2025/07/a7bbfe0d796ccd16fbe1cb20ee865bb9.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"505": {
|
||||
"id": 505,
|
||||
"name": "Coarse Hilbert Wiper",
|
||||
@@ -1370,6 +1410,22 @@
|
||||
"1": 2550
|
||||
}
|
||||
},
|
||||
"8573": {
|
||||
"id": 8573,
|
||||
"name": "Coffee Table Spiral In to Out",
|
||||
"author": "Oasis Mini",
|
||||
"image": "2025/07/3ab8079a9fcd56febcfcb0caa8a033e7.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"8574": {
|
||||
"id": 8574,
|
||||
"name": "Coffee Table Spiral Out to In",
|
||||
"author": "Oasis Mini",
|
||||
"image": "2025/07/6dc91c7431d03817425010d2beffde8e.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"1300": {
|
||||
"id": 1300,
|
||||
"name": "Collapse",
|
||||
@@ -3158,6 +3214,14 @@
|
||||
"1": 22478
|
||||
}
|
||||
},
|
||||
"8510": {
|
||||
"id": 8510,
|
||||
"name": "Heartleaf Philodendron",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/07/c5256b608155eb20cf4a26bc78a8a62c.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"6414": {
|
||||
"id": 6414,
|
||||
"name": "Hearts",
|
||||
@@ -3209,6 +3273,14 @@
|
||||
"1": 67309
|
||||
}
|
||||
},
|
||||
"8498": {
|
||||
"id": 8498,
|
||||
"name": "Hibiscus Flower",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/111f43d73c3dfe1cd836ee70592b7673.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"147": {
|
||||
"id": 147,
|
||||
"name": "Hilbert",
|
||||
@@ -3417,6 +3489,14 @@
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"8403": {
|
||||
"id": 8403,
|
||||
"name": "Imaginative Sand Drawning",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/180e2727632e3e92791e8160f993c550.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"2686": {
|
||||
"id": 2686,
|
||||
"name": "Infinite Rose",
|
||||
@@ -3992,6 +4072,14 @@
|
||||
"1": 44947
|
||||
}
|
||||
},
|
||||
"8425": {
|
||||
"id": 8425,
|
||||
"name": "Mammoth",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/b8a285c6ad730abaa0d89690be5abb38.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"64": {
|
||||
"id": 64,
|
||||
"name": "Mandala",
|
||||
@@ -4268,6 +4356,14 @@
|
||||
},
|
||||
"updated_at": "2024-08-04T15:58:53.000000Z"
|
||||
},
|
||||
"8508": {
|
||||
"id": 8508,
|
||||
"name": "Monstera Deliciosa",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/07/af2e6ac2a5c92705eb8f2fcfea5ac928.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"1778": {
|
||||
"id": 1778,
|
||||
"name": "Monstera leaves",
|
||||
@@ -4577,6 +4673,22 @@
|
||||
"1": 29643
|
||||
}
|
||||
},
|
||||
"8491": {
|
||||
"id": 8491,
|
||||
"name": "Passion Flower",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/f743035a2c869d16267e18feba47371b.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"8502": {
|
||||
"id": 8502,
|
||||
"name": "Passion Flower power",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/e87580e434cc8cec9c4c28bcf1c0acd2.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"221": {
|
||||
"id": 221,
|
||||
"name": "Pattern 3",
|
||||
@@ -4832,6 +4944,14 @@
|
||||
"1": 24258
|
||||
}
|
||||
},
|
||||
"8483": {
|
||||
"id": 8483,
|
||||
"name": "Poison Ivy",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/d33ab742dfe9ce327a7a9746e1a8a096.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"1049": {
|
||||
"id": 1049,
|
||||
"name": "PolarValentine",
|
||||
@@ -4842,6 +4962,14 @@
|
||||
"1": 29754
|
||||
}
|
||||
},
|
||||
"8464": {
|
||||
"id": 8464,
|
||||
"name": "Polka Dot Begonia",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/46cd2ffdf53ab439af8edd4ccecad3be.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"995": {
|
||||
"id": 995,
|
||||
"name": "Polygon Fisheye",
|
||||
@@ -4852,6 +4980,14 @@
|
||||
"1": 7020
|
||||
}
|
||||
},
|
||||
"8588": {
|
||||
"id": 8588,
|
||||
"name": "Polygons",
|
||||
"author": "Walter Melanson",
|
||||
"image": "2025/07/eee6096038e9b6a70808fdddcbe1fef7.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"559": {
|
||||
"id": 559,
|
||||
"name": "Polymath",
|
||||
@@ -4904,6 +5040,14 @@
|
||||
"1": 33688
|
||||
}
|
||||
},
|
||||
"8431": {
|
||||
"id": 8431,
|
||||
"name": "Pufferfish",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/b97dcd4158361728d4908fcff652ead7.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"5184": {
|
||||
"id": 5184,
|
||||
"name": "Pyrohedron",
|
||||
@@ -5503,6 +5647,22 @@
|
||||
"1": 4665
|
||||
}
|
||||
},
|
||||
"8575": {
|
||||
"id": 8575,
|
||||
"name": "Side Table Spiral In to Out",
|
||||
"author": "Oasis Mini",
|
||||
"image": "2025/07/f3956248c0f7f5c281c52d85b7654ec9.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"8576": {
|
||||
"id": 8576,
|
||||
"name": "Side Table Spiral Out to In",
|
||||
"author": "Oasis Mini",
|
||||
"image": "2025/07/ffb61a26562e26efb34f8706c7ba52ec.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"149": {
|
||||
"id": 149,
|
||||
"name": "Sierpenski",
|
||||
@@ -6270,6 +6430,14 @@
|
||||
"1": 3187
|
||||
}
|
||||
},
|
||||
"8459": {
|
||||
"id": 8459,
|
||||
"name": "Spoted Rex Begonia",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/5a16cae9f3a6b5d870a6e2a6fd4506fe.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"3047": {
|
||||
"id": 3047,
|
||||
"name": "Sprioneering",
|
||||
@@ -6914,6 +7082,14 @@
|
||||
},
|
||||
"updated_at": "2024-08-04T15:58:54.000000Z"
|
||||
},
|
||||
"8497": {
|
||||
"id": 8497,
|
||||
"name": "T-Rex Skull",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/8f6e693fa071f8be3b084032d78580a1.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"7276": {
|
||||
"id": 7276,
|
||||
"name": "Takeshi Ren",
|
||||
@@ -7032,6 +7208,14 @@
|
||||
"1": 58681
|
||||
}
|
||||
},
|
||||
"8428": {
|
||||
"id": 8428,
|
||||
"name": "The Buddah’s Head 2",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/71bad0197fc33b677b29bdd063d50b59.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"6998": {
|
||||
"id": 6998,
|
||||
"name": "The Camel",
|
||||
@@ -8232,6 +8416,14 @@
|
||||
},
|
||||
"updated_at": "2024-08-04T16:01:31.000000Z"
|
||||
},
|
||||
"8488": {
|
||||
"id": 8488,
|
||||
"name": "Zen Bambu and Stones",
|
||||
"author": "Otávio Bittencourt",
|
||||
"image": "2025/06/21cdeb1f40571b68578afa6844326936.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
},
|
||||
"4014": {
|
||||
"id": 4014,
|
||||
"name": "Zombie",
|
||||
@@ -8241,5 +8433,13 @@
|
||||
"reduced_svg_content": {
|
||||
"1": 21411
|
||||
}
|
||||
},
|
||||
"8593": {
|
||||
"id": 8593,
|
||||
"name": "ZSC Lions Stern",
|
||||
"author": "adi",
|
||||
"image": "2025/07/de61ce519b7e6946ed777d54f521a29c.svg",
|
||||
"clean_pattern": null,
|
||||
"reduced_svg_content": []
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,14 @@ def _bit_to_bool(val: str) -> bool:
|
||||
return val == "1"
|
||||
|
||||
|
||||
def _parse_int(val: str) -> int:
|
||||
"""Convert an int string to int."""
|
||||
try:
|
||||
return int(val)
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
|
||||
def draw_svg(track: dict, progress: int, model_id: str) -> str | None:
|
||||
"""Draw SVG."""
|
||||
if track and (svg_content := track.get("svg_content")):
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
"button": {
|
||||
"random_track": {
|
||||
"name": "Play random track"
|
||||
},
|
||||
"sleep": {
|
||||
"name": "Sleep"
|
||||
}
|
||||
},
|
||||
"binary_sensor": {
|
||||
@@ -93,9 +96,11 @@
|
||||
"centering": "Centering",
|
||||
"playing": "Playing",
|
||||
"paused": "Paused",
|
||||
"sleeping": "Sleeping",
|
||||
"error": "Error",
|
||||
"updating": "Updating",
|
||||
"downloading": "Downloading",
|
||||
"busy": "Busy",
|
||||
"live": "Live drawing"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
"button": {
|
||||
"random_track": {
|
||||
"name": "Play random track"
|
||||
},
|
||||
"sleep": {
|
||||
"name": "Sleep"
|
||||
}
|
||||
},
|
||||
"binary_sensor": {
|
||||
@@ -93,9 +96,11 @@
|
||||
"centering": "Centering",
|
||||
"playing": "Playing",
|
||||
"paused": "Paused",
|
||||
"sleeping": "Sleeping",
|
||||
"error": "Error",
|
||||
"updating": "Updating",
|
||||
"downloading": "Downloading",
|
||||
"busy": "Busy",
|
||||
"live": "Live drawing"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user