Pychonet
A Python library for interfacing with the ECHONET Lite protocol as commonly used in Japan. Useful for interfacing with HVACs, lighting systems, electric car chargers, solar systems, distribution panel meters, water heaters, and many other devices that support ECHONET Lite.
Designed to work with Python 3.9+. Built on asyncio for compatibility with Home Assistant and other async frameworks.
Installation
pip install pychonet
Basic Usage
Start the ECHONET Lite listener
import asyncio
from pychonet.lib.udpserver import UDPServer
from pychonet import ECHONETAPIClient as api
udp = UDPServer()
loop = asyncio.get_event_loop()
udp.run("0.0.0.0", 3610, loop=loop)
server = api(server=udp)
Configure the client
import logging
_LOGGER = logging.getLogger(__name__)
server.configure(
message_timeout=50, # 50 ticks × 0.1s = 5s per request (default: 200 = 20s)
logger=_LOGGER.debug, # route pychonet logs to your logger
debug=True, # enable verbose internal logging
discover_callback=my_cb, # async callback when unknown host is detected
)
Discover devices
# Discover instances on a host
await server.discover('192.168.1.6')
# Register multicast for the interface used to reach a host
server.register_multicast('192.168.1.6')
Pre-populate instance state (without network discovery)
Useful when restoring known device state from stored configuration:
server.register_instance(
host='192.168.1.6',
eojgc=1, eojcc=48, eojci=1,
ntfmap=[0x80, 0x81, 0x88], # STATMAP — EPCs the device pushes notifications for
setmap=[0x80, 0x81, 0xB3], # SETMAP
getmap=[0x80, 0x81, 0x88, 0xB3, 0xBB], # GETMAP
uid='abc123',
)
Unregister a host (e.g. on shutdown)
server.unregister_host('192.168.1.6')
Create a device instance
from pychonet import Factory
# Using the Factory (recommended — selects the correct class automatically)
device = Factory('192.168.1.6', server, 1, 48, 1)
# Or directly
from pychonet import HomeAirConditioner
aircon = HomeAirConditioner('192.168.1.6', server)
Read EPC values
# Read all supported EPCs
data = await device.update()
# Read specific EPCs
data = await device.update([0x80, 0xBB, 0xB3])
# Read from local cache (no network request)
data = await device.update([0x80], no_request=True)
Write EPC values
# Set a single EPC
await device.setMessage(0x80, b'\x30') # operating status = on
# Set multiple EPCs
await device.setMessages([
{'EPC': 0x80, 'EDT': b'\x30'},
{'EPC': 0xB3, 'EDT': b'\x41'},
])
Register custom EPC decode functions (quirks)
For devices with non-standard EPC behaviour, register instance-level overrides:
def my_custom_decoder(edt):
return {'value': int.from_bytes(edt, 'big')}
device.register_epc_function(0xB3, my_custom_decoder)
This creates an instance-level override — the custom function only applies to this device instance, not all instances of the same device class.
Push notifications
Register a callback to receive unsolicited INF packets from the device:
async def on_update(isPush: bool):
data = await device.update([0x80, 0x88], no_request=True)
print(f"Device state changed: {data}")
server.register_async_update_callbacks('192.168.1.6', 1, 48, 1, on_update)
Unregister when done:
server.unregister_async_update_callbacks('192.168.1.6', 1, 48, 1)
Populate property maps
await server.getAllPropertyMaps('192.168.1.6', 1, 48, 1)
Return values from update()
| Return value | Meaning |
|---|---|
dict |
Success — EPC values keyed by EPC code |
None |
pychonet _waiting queue was busy — request not sent, serve cached data |
Raises TimeoutError |
Request sent but device did not respond |
None (queue busy) should be treated as a cache-serve rather than an error. A TimeoutError
indicates the device genuinely did not respond within message_timeout ticks.
Device Classes
pychonet includes classes for many ECHONET Lite device types. Each class provides
an EPC_FUNCTIONS dict mapping EPC codes to decode functions, and inherits the
generic update() and setMessage() API from EchonetInstance.
Use Factory() to automatically select the correct class based on eojgc/eojcc:
from pychonet import Factory
device = Factory(host, server, eojgc, eojcc, eojci)
For device types not yet supported, EchonetInstance provides raw connectivity
and the generic update()/setMessage() API works for any EPC.
Using with Home Assistant
For Home Assistant users there is a dedicated integration installable via HACS:
https://github.com/scottyphillips/echonetlite_homeassistant
Hall of Fame
Big thanks to Naoki Sawada (nao-pon) for many excellent updates including push notification support via multicast. どうもありがとうございます!
Thanks to Jason Nader for quality of life updates to the codebase and documentation.
Thanks to khcnz (Karl Chaffey) and gvs for helping refactor the old code and contributing to testing.
Thanks to Dick Swart, Masaki Tagawa, Paul, khcnz, Kolodnerd, Leonunix, and Alfie Gerner for contributing code updates to this library.
Thanks to Jeffro Carr who inspired me to write a native Python ECHONET library for Home Assistant.
Thanks to Futomi Hatano for open sourcing a well-documented ECHONET Lite library in Node JS: https://github.com/futomi/node-echonet-lite
Extra Special thanks to 'sayurin' for offering up so many constructive ideas on how to make this project better,
References
- ECHONET Lite Specification, Version 1.13
- APPENDIX, Detailed Requirements for ECHONET Device objects, Release Q
- Machine Readable Appendix (MRA)
License
MIT License — refer to LICENSE for details.
Portions of 'ECHONET Lite Device Emulator' (Copyright 2020 Kanagawa Institute of Technology) have been used. Licensed under MIT.
The UDP code is based on 'aio-udp-server' (Copyright 2021 Dmitriy Bashkirtsev). Licensed under GPL: https://github.com/bashkirtsevich-llc/aioudp
Metadata
Release files for pychonet 2.8.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pychonet-2.8.1.tar.gz | 135.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pychonet-2.8.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 265.8 kB
Release files / pychonet-2.8.1.tar.gz
| Download URL | pychonet-2.8.1.tar.gz |
|---|---|
| Size | 135.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6b0891883af326d38e8ccb0e60e2d07781879eaccc993832739cae44b33bac28
|
|
BLAKE2b-256 checksum How to use checksums |
e86b0ae4ef0de49350ef89ae11fe3347b5a85e5ab177be56d5c12a45d994b0e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.5
|
Release files / pychonet-2.8.1-py3-none-any.whl
| Download URL | pychonet-2.8.1-py3-none-any.whl |
|---|---|
| Size | 130.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cfdd904722389fe22accf05e9f3bb8ecf6d2244a722bc6d4fe8e124b9ceffc52
|
|
BLAKE2b-256 checksum How to use checksums |
80b1ed7cc4947065afcd66fa36b21bde3f96d9cce4b310151d70a79c0576a4bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.5
|