Skip to content

Instantly share code, notes, and snippets.

@miditkl
Created January 25, 2026 11:51
Show Gist options
  • Select an option

  • Save miditkl/f44cd08bd0c47982fcdb67c7451a939a to your computer and use it in GitHub Desktop.

Select an option

Save miditkl/f44cd08bd0c47982fcdb67c7451a939a to your computer and use it in GitHub Desktop.
This script logs into your De'Longhi account, retrieves an authentication token, and then fetches information about your registered coffee machines or other De'Longhi comfort devices.
#!/usr/bin/env python3
"""
De'Longhi Device Info Retriever
This script logs into your De'Longhi account, retrieves an authentication token,
and then fetches information about your registered coffee machines or other
De'Longhi comfort devices.
It's designed as a simple, command-line tool that leaves no trace on your system,
as it cleans up the temporary token file it creates.
---
Installation:
You need to install two Python libraries. You can do this using pip:
pip install requests cremalink
---
How to run:
Save this file (e.g., as `delonghi_device_info.py`) and run it from your terminal:
python delonghi_device_info.py
The script will then prompt you for your De'Longhi account email and password.
"""
import requests
import base64
from datetime import datetime
import urllib.parse
import json
import tempfile
import os
import sys
import getpass
from cremalink import Client
def get_refresh_token(email, password):
"""Performs the full authentication flow to get a refresh token."""
print("Authenticating...")
# --- Constants and Headers ---
SDK_BUILD = 16650
API_KEY = "3_e5qn7USZK-QtsIso1wCelqUKAK_IVEsYshRIssQ-X-k55haiZXmKWDHDRul2e5Y2"
CLIENT_ID = "1S8q1WJEs-emOB43Z0-66WnL"
CLIENT_SECRET = "lmnceiD0B-4KPNN5ZS6WuWU70j9V5BCuSlz2OPsvHkyLryhMkJkPvKsivfTq3RfNYj8GpCELtOBvhaDIzKcBtg"
AUTHORIZATION_HEADER = ("Basic " + base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode()).decode())
APP_ID = "DeLonghiComfort2-mw-id"
APP_SECRET = "DeLonghiComfort2-Yg4miiqiNcf0Or-EhJwRh7ACfBY"
BROWSER_USER_AGENT = "DeLonghiComfort/5.1.1"
def get_query_param(url, param):
"""Extracts a query parameter from a URL."""
return urllib.parse.parse_qs(urllib.parse.urlparse(url).query).get(param, [None])[0]
auth_response = requests.get(
f"https://fidm.eu1.gigya.com/oidc/op/v1.0/{API_KEY}/authorize",
headers={"User-Agent": BROWSER_USER_AGENT},
params={"client_id": CLIENT_ID, "response_type": "code", "redirect_uri": "https://google.it",
"scope": "openid email profile UID comfort en alexa", "nonce": str(int(datetime.now().timestamp()))},
allow_redirects=False,
)
context = get_query_param(auth_response.headers["Location"], "context")
gigya_session_response = requests.get(
f"https://socialize.eu1.gigya.com/socialize.getIDs",
headers={"User-Agent": BROWSER_USER_AGENT},
params={"APIKey": API_KEY, "includeTicket": True, "pageURL": "https://aylaopenid.delonghigroup.com/",
"sdk": "js_latest", "sdkBuild": SDK_BUILD, "format": "json"},
).json()
ucid, gmid, gmid_ticket = gigya_session_response["ucid"], gigya_session_response["gmid"], gigya_session_response[
"gmidTicket"]
login_response = requests.post(
"https://accounts.eu1.gigya.com/accounts.login",
headers={"User-Agent": BROWSER_USER_AGENT},
data={"loginID": email, "password": password, "sessionExpiration": 7884009, "targetEnv": "jssdk",
"include": "profile,data,emails,subscriptions,preferences", "includeUserInfo": True,
"loginMode": "standard", "APIKey": API_KEY, "source": "showScreenSet", "sdk": "js_latest",
"authMode": "cookie", "pageURL": "https://aylaopenid.delonghigroup.com/", "gmid": gmid, "ucid": ucid,
"sdkBuild": SDK_BUILD, "format": "json"},
).json()
login_token = login_response["sessionInfo"]["login_token"]
user_info_response = requests.post(
"https://socialize.eu1.gigya.com/socialize.getUserInfo",
headers={"User-Agent": BROWSER_USER_AGENT},
data={"enabledProviders": "*", "APIKey": API_KEY, "sdk": "js_latest", "login_token": login_token,
"authMode": "cookie", "pageURL": "https://aylaopenid.delonghigroup.com/", "gmid": gmid, "ucid": ucid,
"sdkBuild": SDK_BUILD, "format": "json"},
).json()
user_uid, user_uid_signature, user_signature_timestamp = user_info_response["UID"], user_info_response[
"UIDSignature"], user_info_response["signatureTimestamp"]
consent_response = requests.get(
f"https://aylaopenid.delonghigroup.com/OIDCConsentPage.php",
headers={"User-Agent": BROWSER_USER_AGENT},
params={"context": context, "clientID": CLIENT_ID, "scope": "openid+email+profile+UID+comfort+en+alexa",
"UID": user_uid, "UIDSignature": user_uid_signature, "signatureTimestamp": user_signature_timestamp},
).text
signature = consent_response.split("const consentObj2Sig = '")[1].split("';")[0]
auth_continue_response = requests.get(
f"https://fidm.eu1.gigya.com/oidc/op/v1.0/{API_KEY}/authorize/continue",
headers={"User-Agent": BROWSER_USER_AGENT},
params={"context": context, "login_token": login_token, "consent": json.dumps(
{"scope": "openid email profile UID comfort en alexa", "clientID": CLIENT_ID, "context": context,
"UID": user_uid, "consent": True}, separators=(",", ":")), "sig": signature, "gmidTicket": gmid_ticket},
allow_redirects=False,
)
code = get_query_param(auth_continue_response.headers["Location"], "code")
idp_token_response = requests.post(
f"https://fidm.eu1.gigya.com/oidc/op/v1.0/{API_KEY}/token",
headers={"User-Agent": BROWSER_USER_AGENT, "Authorization": AUTHORIZATION_HEADER,
"Content-Type": "application/x-www-form-urlencoded"},
data={"code": code, "grant_type": "authorization_code", "redirect_uri": "https://google.it"},
).json()
idp_token = idp_token_response["access_token"]
ayla_token_response = requests.post(
"https://user-field-eu.aylanetworks.com/api/v1/token_sign_in",
headers={"User-Agent": BROWSER_USER_AGENT},
data={"app_id": APP_ID, "app_secret": APP_SECRET, "token": idp_token},
).json()
print("Authentication successful!")
return ayla_token_response["refresh_token"]
def main():
"""Main function to run the CLI application."""
print("De'Longhi Device Info Retriever")
print("===============================\n")
temp_token_path = None
try:
email = input("Email: ")
if sys.stdin.isatty():
password = getpass.getpass("Password: ")
else:
print("Warning: Running in a non-interactive environment. Password will be visible.")
password = input("Password: ")
refresh_token = get_refresh_token(email, password)
# Create a temporary file, write to it, and close it.
# delete=False is important for Windows compatibility.
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json', encoding='utf-8') as temp_token_file:
temp_token_path = temp_token_file.name
json.dump({"refresh_token": refresh_token}, temp_token_file)
print("\nFetching device information...")
client = Client(token_path=temp_token_path)
dsns = client.get_devices()
if not dsns:
print("No devices found.")
return
for dsn in dsns:
device = client.get_device(dsn)
print(f"---------------------------------")
print(f" Model: {device.model}")
print(f" DSN: {device.dsn}")
print(f" Local IP address: {device.ip}")
print(f" Lan Key: {device.lan_key}")
print(f"---------------------------------")
except requests.exceptions.RequestException as e:
print(f"\nAn error occurred with the network request: {e}")
except KeyError as e:
print(f"\nAn error occurred: Could not find expected data in the response. {e}")
except Exception as e:
print(f"\nAn unexpected error occurred: {e}")
finally:
# Clean up the temporary file manually
if temp_token_path and os.path.exists(temp_token_path):
os.remove(temp_token_path)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment