Release History¶
Unreleased¶
the adapter is in every binding:
ciplink.Adapterin Python,ciplink_adapter_startand the otherciplink_adapter_*functions in C,ciplink::Adapterin C++ andCiplink.Adapterin C#, with the Rust core's events, connections and stats. See Adapter.browsing marks ciplink devices:
browse_portandscan_portread the ciplink object of every device found at an IP address, so a node has anapp(name, version, status text, assemblies, connections and asummaryline);get_app(route)reads it for one device (app_atin Rust,GetAppin C#,ciplink_get_appin C).examples/device_browser.pyshows the badge and app line.the wiki is published from main whenever the docs change (a tag cannot deploy to the github-pages environment).
the adapter's socket tests no longer flake on Windows: test scanners pick their own T→O connection IDs, and port 0 tries random ports, since Windows reserves blocks of UDP ports.
ciplink 0.3.5¶
an opt-in EtherNet/IP adapter role in the Rust core (
ciplink::adapter): an application that starts anAdapteranswers Forward Open and exchanges class 1 I/O, so a Logix controller can own it in its I/O tree like an I/O module. Nothing listens unless an app starts one. Bindings follow. See Adapter.the docs are a MkDocs wiki on GitHub Pages, with Python, Rust, C#, C++ and C examples in every guide.
a fragmented template or trend read no longer logs
ERROR ... Insufficient Packet Spacefor each piece: a generic message reply with general status 0x06 (partial transfer, more to read) logs at debug. Real failures still log at error.
ciplink 0.3.4¶
ciplink-server: the tag server on the Rust core, a port of the Python ciplink-tagserver 0.4 with the same config files, WebSocket protocol and HTTP API (@ciplink/reactapps work unchanged). It comes with every binding: theciplink-servercommand andciplink.server.TagServerin the Python package, theciplink-servercrate,ciplink_server_startin C,ciplink::Serverin C++ andCiplink.TagServerin C#, and an executable per platform on the GitHub release. See Tag server.scalar bit strings are no longer taken for BOOL arrays: a
DWORDread by name gives its 32 bits (not bit 0),Name.nreads bit n of aBYTE,WORD,DWORDorLWORD(a tag, member or array element) and writes it with a Read-Modify-Write ofNameitself. Only aDWORDwith dimensions is a BOOL array.ciplink-simhasBYTE,WORDandLWORDtags and members.ciplink-simlists a BOOL array tag's dimensions in the 32-bit words that hold it, as controllers do (aBOOL[64]is[2]), not in BOOLs.
ciplink 0.3.3¶
device browsing like RSWho:
get_ports(),browse_port(),iter_port()andget_identity()list a device's ports, the modules, nodes or (on an EtherNet/IP port) the devices of its subnet, and the identity at any route through them, probing from several connections at once. Every binding has it: Python and Rust, C++ (get_ports,browse_port,scan_port), C# (GetPorts,BrowsePort,ScanPort) and C (ciplink_get_ports,ciplink_browse_port,ciplink_scan_port).examples/device_browser.pyis a tree browser built on them.discover()broadcasts on every network adapter that is up, not only on the addresses the host name resolves to (which can leave out a plant network adapter with a static address), and on all of them at once.ciplink-simanswers the Port Object and TCP/IP Interface Object (a backplane and an EtherNet/IP port);chassis_sizesets the slots of its backplane,ip/netmaskits port andnetworkthe devices on its network.
ciplink 0.3.2¶
controller-side trends: the controller samples tags at a fixed period (down to 1 ms) into the trend object Studio 5000 uses, and the driver uploads the samples in batches on a connection of its own, each with the controller's timestamp. A pen is any atomic tag, member or array element of up to 32 bits (BOOL, SINT, INT, DINT, USINT, UINT, UDINT, REAL) or a bit; 64-bit types cannot be trended.
LogixDriver.trend()in Python, Rust and C++,LogixDriver.Trend()in C#,ciplink_trend_startin C.ciplink-simsimulates the trend object.
ciplink 0.3.1¶
the NuGet package now has a README and links to the project and its repository.
ciplink 0.3.0¶
the driver core is written in Rust (
crates/ciplink) and the Python package drives it through the extension moduleciplink._core. The Python API, the requests sent (byte for byte), the results and the error messages are those of 0.2.0; reads and writes take a third to a quarter of the client CPU, and opening a connection with a large tag list (or from the tag cache file) is four to six times faster. The GIL is released during network I/O.the same core is available from C (
ciplink.h), C++ (header-onlyciplink.hpp), C# (.NET 8+) and Rust, seebindings/README.md.ciplink-sim, a simulated Logix, Micro800 or SLC 500 controller for tests in any language.[Breaking] the wheels are platform specific (abi3, one per platform for Python 3.9+), and installing from source needs a Rust toolchain. Driver internals the Python driver had (
_sock,send,_forward_open,_read_tag,encode_value...) are gone; code that patched them must use the public API.
ciplink 0.2.0¶
LogixDriver¶
every
read,write,get_tag_descriptionandauthenticate_metadataerror is aTagError, astrwith akind(ErrorKind) and the CIPstatusand first extended status wordextof a controller error.Tag.error_kindis the kind,Nonewithout an error andOTHERfor a plain string. Kinds:NOT_FOUND(no such tag, member, element or bit),BAD_VALUE(the write value does not fit the type),BAD_REQUEST(malformed request),ACCESS(privilege, AOI local tag, keyswitch or password),REFUSED(nothing done, retry later: reload backoff, state conflict, upload/download mode),TABLE_CHANGED(the tag table changed during the request),COMM(request or reply lost or unparseable),DEVICE(any other controller status) andOTHER. The error messages are unchanged.-
[Breaking] write values are checked strictly, a value that does not fit is rejected for that tag (
BAD_VALUE, nothing is sent for it, the other tags are still written): -
an array given more values than elements (it was truncated)
- BOOL values other than
True/Falseor the ints0/1(any truthy value set the bit), also for BOOL arrays, bit members of structures and bits of integers True/Falsefor an integer,REALorLREAL- a structure dict with keys that are not members (they were ignored)
The BOOL and number checks are in the data types, so SLCDriver word writes reject True/False too
(write('N7:0', True), write 1), bit writes like B3:0/1 still take any value.
-
get_tag_descriptions(*tag_names) reads many Descriptions at once, a list of the same results as
get_tag_description of each tag, sending one round of multi-service packets per candidate path (element,
member, base) instead of one request per tag and path. get_tag_description uses it.
1.3.0 (unreleased)¶
[Breaking] a request that fails with a
CommError(timeout, connection reset) now closes the connection, callopen()again to reconnect. Awithblock raisesCommErrorif the connection cannot be opened.requests on one driver are sent one at a time, so a driver can be shared between threads
fixed
STRING2, emptySTRINGN,DATE_AND_TIMEinside structs and signedTIME32; data shorter than the type now raisesDataErrorconfigure_default_loggerreplaces the handlers of a previous call instead of adding more
CIPDriver¶
[Breaking]
generic_messageonly usesroute_pathwithunconnected_send=True, any other path must be part ofrequest_datageneric_messagereplies without data (e.g.Set_Attribute_Single) no longer fail whendata_typeis set, the value isb''list_identityno longer uploads the tag list when called onLogixDriverand always closes its connectionadded
socket_timeoutandconnection_sizekeyword arguments
LogixDriver¶
added
lazy_tags=Trueto load tag definitions on demand instead of uploading them on connectBOOL array slices that do not start or end on a 32-bit boundary can be read and written
one-dimensional arrays with more than 65,535 elements are split into several requests
tag names are case-insensitive (an exact match is tried first)
write()keeps the call order, pending bit masks are sent before a following whole-value writemulti-service packets are sized by their exact request and reply bytes, a partial reply is read again as a fragmented read
array indexes and instance ids above 65535 (32-bit) are encoded correctly
writing a string or
Noneto a BOOL or a bit returns an error instead of writingTruea failed
open()closes the connection, connection errors during init and tag upload are raised asCommError
SLCDriver¶
fixed
B3/nbit addresses and writes to timer/counter.PRE/.ACCSTstring writes send the full 84-byte elementinvalid addresses like
N7:1000are rejected instead of being read as another addressuses the standard Forward Open directly
1.2.16¶
added
DT,LDTandTIME32data types #332
LogixDriver¶
get_plc_timereads the UTC system time (attribute 6) and returns a timezone-awaredatetime, in local time unlesstzis given #276 #306added
tag_namespace_filterto only upload tags whose name starts with a prefix #312
SLCDriver¶
fixed odd-length string writes and garbage data on string reads #331
1.2.14¶
add support for hostnames in connection path
1.2.13¶
CIPDriver¶
add ability to specify broadcast address for
discover()#292 @tlf30
1.2.11¶
update vendor id list #257 @PhilippHaefele
1.2.10¶
CIPDriver¶
support port customization in the connection path
support comma delimiters in the connection path
1.2.9¶
SLCDriver¶
added
get_datalog_queuemethod @ddeckerCPF
1.2.8¶
LogixDriver¶
fixed issue reading single elements >32 from BOOL arrays
1.2.7¶
LogixDriver¶
fixed issue with program-scoped tags in
get_tag_info#216
1.2.6¶
LogixDriver¶
fixed issue handling BOOLs in some predefined types #197
1.2.5¶
LogixDriver¶
fixed issue parsing struct definitions for predefined types for v32+ #186
1.2.4¶
LogixDriver¶
fixed issue for BOOL members inside structures that was introduced as part of 1.2.3 #182
1.2.3¶
LogixDriver¶
fixed issue with bit-level access to integers inside nested structs #170
1.2.2¶
CIPDriver¶
added support for string CIP paths in
generic_messageforroute_pathfixed bug where errors during discovery prevent any results from being returned
fixed issue where
get_module_infowould always use first hop in path instead of the last
LogixDriver¶
fixed issue with multi-request message size tracking being off by 2 bytes
fixed issue with AOI structure handling with > 8 BOOL members being mapped to types larger than a USINT (SISAutomationIMA)
1.2.1¶
added ability to configure custom logger via the
configure_default_loggerfunction
1.2.0¶
fixed issue with logging configuration
formatted project with black
misc. documentation updates
LogixDriver¶
fixed issue with writing a tag multiple times failing after the first write
added
tags_jsonproperty
SLCDriver¶
fixed issue with parsing IO addresses
improved address parsing speed by pre-compiling regex
1.1.1¶
LogixDriver¶
fixed read/write errors by preventing program-scoped tags from using instance ids in the request
1.1.0¶
LogixDriver¶
fixed bugs in handling of built-in types (TIMER, CONTROL, etc)
fixed bugs in structure tag handling when padding exists between attributes
changed the meaning of the element count for BOOL arrays
- Previously, the
{#}referred to the underlyingDWORDelements of theBOOLarray. ABOOL[64]array is actually aDWORD[2]array, soarray{1}translated to BOOL elements 0-31 or the firstDWORDelement. Now, the{#}refers to the number ofBOOLelements. Soarray{1}is only a singleBOOLelement andarray{32}would be the 0-31BOOLelements. - Refer to BOOL arrays for limitations on writing.
- Previously, the
1.0.1¶
Fixed incorrect/no error in response Tag for some failed requests in a multi-request
Minor refactor to status and extended status parsing
1.0.0¶
New type system to replace the
PackandUnpackhelper classes- New types represent any CIP type or object and allow encoding and decoding of values
- Allows users to create their own custom types
[Breaking]
generic_messagereplaced thedata_formatargument withdata_type, see documentation for details.
Added a new
discover()method for finding Ethernet/IP devices on the local networkAdded a
configure_default_loggermethod for simple logging setup- Packet contents are now logged using a custom
VERBOSElevel
- Packet contents are now logged using a custom
Internal package structure changed.
Lots of refactoring, decoupling, etc
Increased test coverage
New and improved documentation
Still a work-in-progress
Logix Driver¶
Upload of program-scoped tags is now enabled by default
- Use
init_program_tags=Falsein initializer for to upload controller-scoped only tags
- Use
Removed the
init_infoandmicro800init args and theuse_instance_idsproperty- These have all been automatic for awhile now, but were left for backwards compatibility
- If you need to customize this behavior, override the
_initialize_drivermethod