Add Home Assistant integration
Token-authenticated custom component exposing live per-club member counts as sensors under a single "West Wood Club" device, fed by one coordinator polling `/v1/Clubs/WhoIsInCount`. Packaged via `buildHomeAssistantComponent` with a flake package + overlay so it can be used in `services.home-assistant.customComponents`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Regular → Executable
+28
-28
@@ -17,11 +17,11 @@ import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
BASE_URL = "https://goapi2.perfectgym.com"
|
||||
WHITE_LABEL_ID = "7d073db5-0ef8-4d78-89ec-4a8bebaf4cbc"
|
||||
BASE_URL = 'https://goapi2.perfectgym.com'
|
||||
WHITE_LABEL_ID = '7d073db5-0ef8-4d78-89ec-4a8bebaf4cbc'
|
||||
USER_AGENT = (
|
||||
"West Wood Club/1.28.3.0 "
|
||||
"(com.perfectgym.perfectgymgo2.westwoodclub; build:1028003000; Android 16)"
|
||||
'West Wood Club/1.28.3.0 '
|
||||
'(com.perfectgym.perfectgymgo2.westwoodclub; build:1028003000; Android 16)'
|
||||
)
|
||||
|
||||
|
||||
@@ -29,56 +29,56 @@ def log_in(email: str, password: str) -> str:
|
||||
"""Return the bearer token (the value for the Authorization header)."""
|
||||
body = json.dumps(
|
||||
{
|
||||
"email": email,
|
||||
"password": password,
|
||||
"clientApplicationInfo": {
|
||||
"type": "whitelabel",
|
||||
"whiteLabelId": WHITE_LABEL_ID,
|
||||
'email': email,
|
||||
'password': password,
|
||||
'clientApplicationInfo': {
|
||||
'type': 'whitelabel',
|
||||
'whiteLabelId': WHITE_LABEL_ID,
|
||||
},
|
||||
}
|
||||
).encode()
|
||||
|
||||
request = urllib.request.Request(
|
||||
f"{BASE_URL}/v1/Authorize/LogInWithEmail",
|
||||
f'{BASE_URL}/v1/Authorize/LogInWithEmail',
|
||||
data=body,
|
||||
method="POST",
|
||||
method='POST',
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
"Accept-Language": "en",
|
||||
"X-Go-App-Platform": "Android",
|
||||
"X-Go-App-Version": "1.28.3",
|
||||
"X-Go-White-Label-ID": WHITE_LABEL_ID,
|
||||
"User-Agent": USER_AGENT,
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
'Accept-Language': 'en',
|
||||
'X-Go-App-Platform': 'Android',
|
||||
'X-Go-App-Version': '1.28.3',
|
||||
'X-Go-White-Label-ID': WHITE_LABEL_ID,
|
||||
'User-Agent': USER_AGENT,
|
||||
},
|
||||
)
|
||||
|
||||
with urllib.request.urlopen(request) as response:
|
||||
payload = json.load(response)
|
||||
|
||||
if payload.get("errors"):
|
||||
raise SystemExit(f"login failed: {payload['errors']}")
|
||||
if payload.get('errors'):
|
||||
raise SystemExit(f'login failed: {payload["errors"]}')
|
||||
|
||||
data = payload.get("data") or {}
|
||||
token = data.get("token")
|
||||
data = payload.get('data') or {}
|
||||
token = data.get('token')
|
||||
if not token:
|
||||
raise SystemExit(f"no token in response: {payload}")
|
||||
raise SystemExit(f'no token in response: {payload}')
|
||||
return token
|
||||
|
||||
|
||||
def main() -> None:
|
||||
email = os.environ.get("WESTWOOD_EMAIL") or input("Email: ")
|
||||
password = os.environ.get("WESTWOOD_PASSWORD") or getpass.getpass("Password: ")
|
||||
email = os.environ.get('WESTWOOD_EMAIL') or input('Email: ')
|
||||
password = os.environ.get('WESTWOOD_PASSWORD') or getpass.getpass('Password: ')
|
||||
|
||||
try:
|
||||
token = log_in(email, password)
|
||||
except urllib.error.HTTPError as exc:
|
||||
raise SystemExit(f"HTTP {exc.code}: {exc.read().decode('utf-8', 'replace')}")
|
||||
raise SystemExit(f'HTTP {exc.code}: {exc.read().decode("utf-8", "replace")}')
|
||||
except urllib.error.URLError as exc:
|
||||
raise SystemExit(f"request failed: {exc.reason}")
|
||||
raise SystemExit(f'request failed: {exc.reason}')
|
||||
|
||||
print(token)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user