Skip to main content

gehomesdk

Python SDK for GE WiFi-enabled (SmartHQ) appliances. The primary goal is to use this to power integrations for Home Assistant.

Forked from Andrew Mark's repository.

Installation

pip install gehomesdk

Changelog

Please click here for change information.

Usage

gehome-appliance-data

As of 0.5.0, after installation, you should now be able to use the gehome-appliance-data application:

gehome-appliance-data [-h] -u USERNAME -p PASSWORD [-r {US,EU}]

The parameters are as follows:

  • -u or --username: Your SmartHQ Username
  • -p or --password: Your SmartHQ Password
  • -r or --region: Your SmartHQ Region

This application will set up a client, iterate over all appliances, and will update the state every minute. It will also capture all state changes as they happen (useful for figuring out which values correspond to which function). You can exit at any time by keyboard interrupt ctrl^C

Credentials

Create a credentials.py and place in the examples directory. It should contain the following:

USERNAME = "your@email.com"
PASSWORD = "supersecret"
REGION = "US or EU"

You will need to replace the username/password values with your credentials. After that, you can run the websocket_example.py sample file. These will generate information about your appliances and are useful if you'd like to help implement more functionality.

Simple example

Here we're going to run the client in a pre-existing event loop. We're also going to register some event callbacks to update appliances every five minutes and to turn on our oven the first time we see it. Because that is safe!

import aiohttp
import asyncio
import logging
from gehomesdk.secrets import USERNAME, PASSWORD
from gehomesdk import GeWebsocketClient

_LOGGER = logging.getLogger(__name__)


if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(message)s')

    loop = asyncio.get_event_loop()
    client = GeWebsocketClient(USERNAME, PASSWORD, REGION, loop)

    session = aiohttp.ClientSession()
    asyncio.ensure_future(client.async_get_credentials_and_run(session), loop=loop)
    loop.run_until_complete(asyncio.sleep(60))

    for appliance in client.appliances:
        print(appliance)

Authentication

The authentication process has a few steps. First, for both the websocket and XMPP APIs, we use Oauth2 to authenticate to the HTTPS API. From there, we can either get a websocket endpoint with access_token or proceed with the XMPP login flow. For XMPP, we get a mobile device token, which in turn be used to get a new Bearer token, which, finally, is used to get XMPP credentials to authenticate to the Jabber server. In gehomesdk, going from username/password to XMPP credentials is handled by do_full_xmpp_flow(username, password).

Multi-Factor Authentication (MFA)

Some SmartHQ accounts require a one-time verification code (emailed or texted) during login. async_get_oauth2_token and GeBaseClient.async_get_credentials cannot satisfy that challenge on their own and will raise GeAuthMfaRequiredError (with an mfa_methods list of the available verification methods) if one is encountered.

To complete the challenge interactively, use GeSmartHqLogin directly:

from gehomesdk import GeSmartHqLogin

login = GeSmartHqLogin(session)
result = await login.async_login(username, password, region)

if result.mfa_required:
    await login.async_send_code(result.mfa_methods[0])  # e.g. "email"
    code = input("Enter the verification code you received: ")
    token = await login.async_submit_code(code)
else:
    token = result.token

The resulting token dict includes a refresh_token. Pass it to GeWebsocketClient(..., refresh_token=token["refresh_token"]) so future reconnects authenticate via the refresh token instead of repeating the full login, which would re-trigger the MFA challenge. The client also exposes its current refresh_token property so it can be persisted if the SDK rotates it internally.

Useful functions

do_full_xmpp_flow(username, password) ${\textsf{\color{red}!!! DEPRECATED AND REMOVED !!!}}$

Function to authenticate to the web API and get XMPP credentials. Returns a dict of XMPP credentials

do_full_wss_flow(username, password)

Function to authenticate to the web API and get websocket credentials. Returns a dict of WSS credentials

Objects

GeWebsocketClient(event_loop=None, username=None, password=None)

Main Websocket client

  • event_loop: asyncio.AbstractEventLoop Optional event loop. If None, the client will use asyncio.get_event_loop()
  • username/password Optional strings to use when authenticating

Useful Methods

  • async_get_credentials(session, username=None, password=None) Get new WSS credentials using either the specified username and password or ones already set in the constructor.
  • get_credentials(username=None, password=None) Blocking version of the above
  • add_event_handler(event, callback) Add an event handler
  • disconnect() Disconnect the client
  • async_run_client() Run the client
  • async_get_credentials_and_run(sessions, username=None, password=None) Authenticate and run the client

Properties

  • appliances A Dict[str, GeAppliance] of all known appliances keyed on the appliances' JIDs.

Events

  • EVENT_ADD_APPLIANCE - Triggered immediately after a new appliance is added, before the initial update request has even been sent. The GeAppliance object is passed to the callback.
  • EVENT_APPLIANCE_INITIAL_UPDATE - Triggered when an appliance's type changes, at which point we know at least a little about the appliance. The GeAppliance object is passed to the callback.
  • EVENT_APPLIANCE_STATE_CHANGE - Triggered when an appliance message with a new state, different from the existing, cached state is received. A tuple (appliance, state_changes) is passed to the callback, where appliance is the GeAppliance object with the updated state and state_changes is a dictionary {erd_key: new_value} of the changed state.
  • EVENT_APPLIANCE_UPDATE_RECEIVED - Triggered after processing an ERD update message whether or not the state changed
  • EVENT_CONNECTED - Triggered when the API connects, after adding basic subscriptions
  • EVENT_DISCONNECTED - Triggered when the API disconnects
  • EVENT_GOT_APPLIANCE_LIST - Triggered when we get the list of appliances

GeXmppClient(xmpp_credentials, event_loop=None, **kwargs)

${\textsf{\color{red}!!! DEPRECATED AND REMOVED !!! }}$

Main XMPP client, and a subclass of slixmpp.ClientXMPP.

  • xmpp_credentials: dict A dictionary of XMPP credentials, usually obtained from either do_full_login_flow or, in a more manual process, get_xmpp_credentials
  • event_loop: asyncio.AbstractEventLoop Optional event loop. If None, the client will use asyncio.get_event_loop()
  • **kwargs Passed to slixmpp.ClientXMPP

Useful Methods

  • connect() Connect to the XMPP server
  • process_in_running_loop(timeout: Optional[int] = None) Run in an existing event loop. If timeout is given, stop running after timeout seconds
  • add_event_handler(name: str, func: Callable) Add an event handler. In addition to the events supported by slixmpp.ClientXMPP, we've added some more event types detailed below.

Properties

  • appliances A Dict[str, GeAppliance] of all known appliances keyed on the appliances' JIDs.

Events

In addition to the standard slixmpp events, the GeClient object has support for the following:

  • EVENT_ADD_APPLIANCE - Triggered immediately after a new appliance is added, before the initial update request has even been sent. The GeAppliance object is passed to the callback.
  • EVENT_APPLIANCE_INITIAL_UPDATE - Triggered when an appliance's type changes, at which point we know at least a little about the appliance. The GeAppliance object is passed to the callback.
  • EVENT_APPLIANCE_STATE_CHANGE - Triggered when an appliance message with a new state, different from the existing, cached state is received. A tuple (appliance, state_changes) is passed to the callback, where appliance is the GeAppliance object with the updated state and state_changes is a dictionary {erd_key: new_value} of the changed state.

GeAppliance(mac_addr, client)

Representation of a single appliance

  • mac_addr: str The appliance's MAC address, which is what GE uses as unique identifiers
  • client: GeBaseClient The client used to communicate with the device

Useful Methods

  • decode_erd_value(erd_code: ErdCodeType, erd_value: str) Decode a raw ERD property value.
  • encode_erd_value(erd_code: ErdCodeType, erd_value: str) Decode a raw ERD property value.
  • get_erd_value(erd_code: ErdCodeType) Get the cached value of ERD code erd_code. If erd_code is a string, this function will attempt to convert it to an ErdCode object first.
  • async_request_update() Request the appliance send an update of all properties
  • set_available() Mark the appliance as available
  • async_set_erd_value(erd_code: ErdType, value) Tell the device to set the property represented by erd_code to value
  • set_unavailable() Mark the appliance as unavailable
  • update_erd_value(erd_code: ErdType, value) Update the local property cache value for erd_code to value, where value is the not yet decoded hex string sent from the API. Returns True if that is a change in state, False otherwise.
  • update_erd_values(self, erd_values: Dict[ErdCodeType, str]) Update multiple values in the local property cache. Returns a dictionary of changed states or an empty dict if nothing actually changed.

Properties

  • appliance_type: Optional[ErdApplianceType] The type of appliance, None if unknown
  • available: bool True if the appliance is available, otherwise False
  • mac_addr The appliance's MAC address (used as the appliance ID)

Useful Enum types

  • ErdCode Enum of known ERD property codes
  • ErdApplianceType Values for ErdCode.APPLIANCE_TYPE
  • ErdMeasurementUnits Values for ErdCode.TEMPERATURE_UNIT
  • ErdOvenCookMode Possible oven cook modes, used for OvenCookSetting among other things
  • ErdOvenState Values for ErdCode.LOWER_OVEN_CURRENT_STATE and ErdCode.UPPER_OVEN_CURRENT_STATE
  • ErdToasterOvenCookMode Possible toaster oven cook modes, used for ToasterOvenCookSetting
  • ErdToasterOvenSize Possible toaster oven size selections, used for ToasterOvenCookSetting
  • ErdToasterOvenState Values for ErdCode.TOASTER_OVEN_CURRENT_STATE

Other types

  • OvenCookSetting A namedtuple of an ErdOvenCookMode and an int temperature
  • OvenConfiguration A namedtuple of boolean properties representing an oven's physical configuration
  • ToasterOvenCookSetting A namedtuple of an ErdToasterOvenCookMode, int temperature, timedelta cook time, and mode-specific shade, size, item_count, and preferences fields

API Overview

The GE SmartHQ app communicates with devices through (at least) three different APIs: XMPP, HTTP REST, and what they seem to call MQTT (though that's not really accurate). All of them are based around sending (pseudo-)HTTP requests back and forth. Device properties are represented by hex codes (represented by ErdCode objects in gehomesdk), and values are sent as hexadecimal strings without leading "0x", then json encoded as a dictionary. One thing that is important to note is that not all appliances support every API.

For further documentation of appliance commands, please see the GEMaker Github repositories at: https://github.com/GEMakers. Not every appliance has documentation there, but many do, and it is useful for decoding values that you may see coming from the API. There is also another Github repository here that has more information about reverse engineering the GE protocols.

  1. REST - We can access or set most device properties via HTTP REST. Unfortunately, relying on this means we need to result to constantly polling the devices, which is less than desirable, especially, e.g., for ovens that where we want to know exactly when a timer finishes. This API is not directly supported.
  2. Websocket "MQTT" - The WSS "MQTT" API is basically a wrapper around the REST API with the ability to subscribe to a device, meaning that we can treat it as (in Home Assistant lingo) IoT Cloud Push instead of IoT Cloud Polling. In gehomesdk, support for the websocket API is provided by the GeWebsocketClient class.
  3. XMPP - ${\textsf{\color{red}!!! DEPRECATED AND REMOVED !!!}}$ As far as I can tell, there seems to be little, if any, benefit to the XMPP API except that it will notify the client if a new device becomes available. I suspect that this can be achieved with websocket API as well via subscriptions, but have not yet tested. Support for the XMPP API is provided by the GeXmppClient class, based on slixmpp, which it requires as an optional dependency.

XMPP API

${\textsf{\color{red}!!! DEPRECATED AND REMOVED !!!}}$

The device informs the client of a state change by sending a PUBLISH message like this, informing us that the value of property 0x5205 (ErdCode.LOWER_OVEN_KITCHEN_TIMER in gehomesdk) is now "002d" (45 minutes):

<body>
    <publish>
        <method>PUBLISH</method>
        <uri>/UUID/erd/0x5205</uri>
        <json>{"0x5205":"002d"}</json>
    </publish>
</body>

Similarly, we can set the timer to 45 minutes by POSTing to the same "endpoint":

<body>
    <request>
        <method>POST</method>
        <uri>/UUID/erd/0x5205</uri>
        <json>{"0x5205":"002d"}</json>
    </request>
</body>

In gehomesdk, that would handled by the GeAppliance.set_erd_value method:

appliance.async_set_erd_value(ErdCode.LOWER_OVEN_KITCHEN_TIMER, timedelta(minutes=45))

We can also get a specific property, or, more commonly, request a full cache refresh by GETing the /UUID/cache endpoint:

<body>
    <request>
        <id>0</id>
        <method>GET</method>
        <uri>/UUID/cache</uri>
    </request>
</body>

The device will then respond to the GET with a response having a json payload:

<body>
    <response>
        <id>0</id>
        <method>GET</method>
        <uri>/UUID/cache</uri>
        <json>{
            "0x0006":"00",
            "0x0007":"00",
            "0x0008":"07",
            "0x0009":"00",
            "0x000a":"03",
            "0x0089":"",
            ...
        }</json>
    </response>
</body>

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gehomesdk-2026.7.1.tar.gz (113.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gehomesdk-2026.7.1-py3-none-any.whl (224.2 kB view details)

Uploaded Python 3

File details

Details for the file gehomesdk-2026.7.1.tar.gz.

File metadata

  • Download URL: gehomesdk-2026.7.1.tar.gz
  • Upload date:
  • Size: 113.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for gehomesdk-2026.7.1.tar.gz
Algorithm Hash digest
SHA256 803bc0aa00218e3a3e6ba187f136d82cfaa69b856e682600c9300c3acf527e21
MD5 1508755cbf23de7d1f02bd9ee435cb6a
BLAKE2b-256 87889ec9f0ad01a0645bc9e884c84e83e64850b2e086da408fbf12d6137c659d

See more details on using hashes here.

File details

Details for the file gehomesdk-2026.7.1-py3-none-any.whl.

File metadata

  • Download URL: gehomesdk-2026.7.1-py3-none-any.whl
  • Upload date:
  • Size: 224.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for gehomesdk-2026.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 305dacf506d79ec1331d5bb90d8314feb9e229195e0f53022b758c1555ec7619
MD5 2e15be136b97f104d4a2e6f4770839f7
BLAKE2b-256 d665b344c84d782c15e18a7444643017c7397aacb302725195b33c07543a8013

See more details on using hashes here.

Release history Release notifications | RSS feed

2026.8.0

2 files

2026.7.2

2 files

This release

2026.7.1 This release

2 files

2026.7.0

2 files

2026.5.4

2 files

2026.5.3

2 files

2026.5.2

2 files

2026.5.1

2 files

2026.5.0

2 files

2026.2.0

2 files

2025.11.5

2 files

2025.11.4

2 files

2025.11.3

2 files

2025.11.2

2 files

2025.11.1

2 files

2025.11.0

2 files

2025.5.0

2 files

2025.2.2

2 files

2025.2.1

2 files

2025.2.0

2 files

0.5.42

2 files

0.5.41

2 files

0.5.40

2 files

0.5.30

2 files

0.5.29

2 files

0.5.28

2 files

0.5.27

2 files

0.5.26

2 files

0.5.25

2 files

0.5.24

2 files

0.5.23

2 files

0.5.22

2 files

0.5.21

2 files

0.5.20

2 files

0.5.19

2 files

0.5.18

2 files

0.5.17

2 files

0.5.16

2 files

0.5.15

2 files

0.5.14

2 files

0.5.13

2 files

0.5.12

2 files

0.5.11

2 files

0.5.10

2 files

0.5.9

2 files

0.5.8

2 files

0.5.7

2 files

0.5.6

2 files

0.5.5

2 files

0.5.0

2 files

0.4.27

2 files

0.4.26

2 files

0.4.25

2 files

0.4.24

2 files

0.4.23

2 files

0.4.22

2 files

0.4.21

2 files

0.4.20

2 files

0.4.19

2 files

0.4.18

2 files

0.4.17

2 files

0.4.16

2 files

0.4.15

2 files

0.4.14

2 files

0.4.13

2 files

0.4.12

2 files

0.4.11

2 files

0.4.10

2 files

0.4.9

2 files

0.4.8

2 files

0.4.7

2 files

0.4.6

2 files

0.4.5

2 files

0.4.4

2 files

0.4.3

2 files

0.4.2

2 files

0.4.0

2 files

0.3.21

2 files

0.3.20

2 files

0.3.19

2 files

0.3.17

2 files

0.3.16

2 files

0.3.15

2 files

0.3.14

2 files

0.3.13

2 files

0.3.12

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page