Changelog¶
All notable changes to this project are documented here. The format follows Keep a Changelog, and versions follow Semantic Versioning.
2.1.0 - 2026-09-29¶
Structured logs: every record names its kind in an event field and carries its context, so logs can be filtered and
aggregated without parsing messages (e.g. event:serial_error in VictoriaLogs). The events and their fields are listed
in the monitoring guide.
Added¶
eventfield on the library's log records:packet_received,packet_sent,teach_in,base_id_received,base_id_timeout,communicator_started/stopped,client_connected/disconnected,serial_error,processing_error,header_crc_error,data_crc_error,malformed_packet,unknown_profile,unknown_field...- Their context as fields:
base_id;transport,port,hostandclientfor the transports;errorfor serial port errors (also in the message, it was lost);lengthof a corrupted packet;dataandoptional(hex) of a malformed one, to replay it;eepandcommandof an unknown profile;shortcutof an unknown field;outcomeof a teach-in. - Packet records also carry
destination,status,repeater_countandeep. SerialCommunicator.port, the serial port it was opened on.
Changed¶
- The
packet_typeandrorgfields of log records are enum names (RADIO_ERP1,VLD) instead of integers, as inpacket.to_dict(): log queries on their numeric values need updating. - The communicators' started/stopped messages name the port, and the TCP client messages the client's address.
2.0.2 - 2026-09-29¶
Fixed¶
RadioPacket.dbmisNonefor telegrams to send (those built byRadioPacket.create(), the actuators and UTE teach-in responses), instead of -255: their dBm byte is 0xFF, which ESP3 uses when sending, not a signal strength. This also fixesto_dict(), thedbmfield of theSendinglog, andstr(packet), which no longer shows a signal strength when there is none.
2.0.1 - 2026-09-29¶
Fixed¶
statusandrepeater_countof VLD (D2) telegrams: the status was read from the last optional byte (the security level, always 0) instead of the last data byte, so it was always 0. The status is now the last data byte and the repeater count its low nibble for every radio telegram (RPS, 1BS, 4BS, VLD, MSC, UTE...). Decoding is unchanged: no VLD profile has conditions on the status.
2.0.0 - 2026-09-28¶
The 270 profiles of the official EnOcean Alliance specification, an integration API (device registry, packet serialization, actuator commands, teach-in), monitoring (statistics, health, Prometheus, structured logs) and a documentation site. Upgrading from 1.0: see the migration guide.
Breaking changes¶
- The profiles are generated from the official EnOcean Alliance specification (EEP 2.6.8), and
EEP.xmlis replaced byenocean/protocol/profiles/(EEP.xml_rootbyEEP.xml_index;EEP.telegramsloads profiles on access): field shortcuts and value descriptions are the official ones. Renamed shortcuts in previously supported profiles: A5-07-01PIR→PIRS, A5-09-06ACT→Act, A5-09-07PM2.5/PM2.5a→PM25/PM25a, A5-09-0CCONC→Conc, A5-11-02CTS→CST, D2-01-xxDE/DN/EP/QU/MDLSB/MDMSB→de/dn/ep/qu/MD_LSB/MD_MSB, F6-02-04EB/RAO/RBO→EBO/RA0/RB0. 4BS and 1BS profiles now decode their learn bit (LRNB,LRN). Enum descriptions changed (e.g.'Button AI'→'Button AI: "Switch light on" or ...'; ranges read'Output channel (to load): 1');create()still accepts the short label before the colon. Some enum ranges decode to numbers (e.g. D2-05POS: 50.0 %). - Decoding aligned with the specification: A5-20-01 direction 2
TMPscale was inverted, A5-38-08EDIMis a percentage (was the raw value), A5-13-01 only covers weather station telegrams with identifier 1 (the others are A5-13-02 to A5-13-06), F6-02-xx telegrams without the NU bit use the spec's "released / several buttons" variant. SerialCommunicatorrequires itsport(the default was/dev/ttyAMA0, a Raspberry Pi UART).packet.receivedis a timezone-aware UTC datetime, set byPacket.parse_msg()(was a naive local datetime set by the communicator); comparing it with naive datetimes raisesTypeError.Packet(...)raisesTypeErrorfor data or optional data that isn't a list of ints,bytes,bytearrayor a tuple (it was silently replaced by an empty list).- Removed
PACKET.RADIOandPACKET.RADIO_ADVANCED: usePACKET.RADIO_ERP1andPACKET.RADIO_ERP2(PACKET(1).nameis nowRADIO_ERP1). - Removed
enocean.decorators(a test helper). examples/enocean_example.pyis no longer installed as a script.enocean.protocol.eepno longer re-exportsRORG: import it fromenocean.protocol.constants.
Deprecated¶
UTETeachInPacket.channel: usenumber_of_channels.RadioPacket.dBm: usedbm, which isNoneinstead of 0 when the module didn't report the signal strength.
Added¶
- Documentation site (https://j5lien.github.io/enocean/): getting started, concepts, guides, API reference generated from the docstrings (now on the whole public API), migration guide; its examples are run by the tests.
- Profiles are loaded on first use (one file per profile under
enocean/protocol/profiles/): buildingEEP()reads a small index (0.6 ms instead of 16 ms for the single 1.5 MB file), and importingenoceantakes about half the time (__version__is resolved on demand). - 270 profiles, generated from the official specification (205 more than before), with
make eep; profiles missing from or unusable in the spec kept intools/eep_additions.xml(D2-14-30, D2-14-41, F6-10-00, F6-10-01). - Profile variants selected by conditions on data or status bits (e.g. F6-02-02 by T21/NU, D2-01 extended commands by ECID), and enum ranges carrying a scale.
packet.to_dict(): JSON-serializable view of a packet (hex IDs, enum names that don't raise on unknown values, ISO reception time, EEP and decoded values).EEPId(EEPId.parse('D2-01-12')),packet.eep_idandpacket.command: the profile and command variant applied.communicator.learn(timeout, max_devices): a teach-in window answering UTE teach-in requests even withteach_in=False, adding the taught-in devices to the device registry and returning them.SwitchActuator(D2-01:set_output,turn_on,turn_off,query_status) andBlindActuator(D2-05:go_to,stop,query_position) inenocean.actuators, sending from the module's base ID.DeviceRegistry/Device(enocean.devices): known devices and their profiles, default profiles per RORG and ignored devices. Communicators givendevices=deliver packets decoded with their device's profile (packet.device,packet.parsed) and drop ignored devices (packets_ignoredstatistic and metric).- Profile introspection:
EEP().profiles()lists the profiles,EEP().describe('D2-01-12')their variants and fields (kind, position, unit, ranges, enum values). - The public API is importable from the package:
from enocean import SerialCommunicator, RadioPacket, RORG;enocean.__version__. SerialCommunicator(teach_in=...), likeTCPCommunicator.Packet(...)acceptsbytesandbytearraydata.
Fixed¶
- F6-10-00 window handle position read the right bits with wrong labels (now: horizontal/open, up/tilted, down/closed).
create(command=0)ignored the command.- UTE teach-in: deletion requests were answered as accepted teach-ins; they are now answered as deletions (as are
non-specific requests from devices already known), and requests for profiles unknown to
EEP.xmlare refused. - Profiles with several commands (e.g. D2-01-12, D2-05-00): decoding without
command=picks the variant the telegram carries instead of the profile's first one (e.g. a D2-01-12 "set output" command was decoded with the status layout). create(command=...)wrote the command into a field namedCMDonly: A5-13-01 and A5-38-08 packets were sent with command 0.- A5-04-02 temperature scale: raw range 0...250 per the EEP specification (was 0...255, reading up to 1.6 °C low).
UTETeachInPacket.number_of_channelswas never read from the telegram (always 0xFF).Packet(type, bytearray(...))silently lost its data.
1.0.0 - 2026-09-27¶
First release of the j5lien/enocean fork of kipe/enocean, whose last release was 0.60.1.
Breaking changes¶
- Python 3.10 or later is required; Python 2 compatibility code is gone.
EEP.xmlis loaded with the standard library'sxml.etreeinstead of BeautifulSoup:EEP.soupis replaced byEEP.xml_root, andEEP.telegramsholdsxml.etree.ElementTree.Elementobjects.- The
beautifulsoup4andenum-compatdependencies are dropped;pyserial>=3.5is the only dependency. RadioPacket.create()raisesValueErrorfor an unknown VLD profile (wasAttributeError).
Added¶
- EEP profiles: A5-04-02, A5-09-06, A5-09-07, A5-09-0C, A5-12-00, A5-13-01, D2-01-12, D2-14-30, D2-14-41, F6-02-03, F6-02-04.
TCPCommunicatoracceptscallbackandteach_in, likeSerialCommunicator.- Type annotations for the whole package (
py.typed); decoded fields are typed asFieldValue.
Fixed¶
- ESP3 parser: a corrupted header or a stray
0x55no longer makes the parser drop the valid packets that follow; it now resynchronizes on the next sync byte after any CRC error. - Radio packets without optional data (allowed by ESP3, omitted by some gateways) no longer crash the parser.
- Packets too short for their type are returned unparsed instead of raising or being reported as CRC errors.
- Decoding a telegram shorter than its EEP profile no longer raises.
- UTE teach-in received before the base ID is known: the base ID is now requested and the teach-in answered, instead of
blocking the communicator thread, raising
TypeErrorand losing the packet. Communicator.base_idworks with a callback, and no longer reorders the receive queue while fetching the base ID.TCPCommunicatorcrashed on every client connection, and only parsed data once the client disconnected.communicators.utils.send_to_tcp_socketwas broken on Python 3.SerialCommunicatorlogs write errors before stopping.- EEP definitions: D2-01-12 enum values written in binary (default state, external button mode), out-of-range dim
timers and measurement delta ranges; missing telegram length on D2-14-30 and D2-14-41 (
create()failed); an attribute on A5-13-01 that only worked with a case-insensitive parser. SUPPORTED_PROFILES.mdlists every profile again.
Changed¶
- Loading
EEP.xmlis about 20× faster and packet creation/decoding about 5× faster. - Development: uv, pytest (with end-to-end communicator tests on a pseudo-terminal, property-based parser tests and tests over every EEP profile), ruff, mypy, pre-commit hooks, GitHub Actions CI and Dependabot.
0.60.1 - 2021-06-18¶
Last release of kipe/enocean.