or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-messaging.mdcore-operations.mddevice-discovery.mdindex.mdtag-discovery.mdtime-operations.md

index.mddocs/

0

# PyLogix

1

2

A Python communication driver that enables reading and writing data values from tags in Rockwell Automation ControlLogix, CompactLogix, and Micro8xx PLCs over Ethernet I/P. PyLogix provides a simple, Pythonic API for PLC communication without external dependencies, making it ideal for industrial automation applications, data acquisition systems, and monitoring tools.

3

4

## Package Information

5

6

- **Package Name**: pylogix

7

- **Language**: Python

8

- **Installation**: `pip install pylogix`

9

- **Compatibility**: Python 2.7, Python 3.x, MicroPython 1.20.0+

10

- **Dependencies**: None (standard library only)

11

12

## Core Imports

13

14

```python

15

from pylogix import PLC

16

```

17

18

Alternative imports for specific components:

19

20

```python

21

from pylogix.eip import PLC

22

from pylogix.lgx_response import Response

23

from pylogix.lgx_tag import Tag, UDT

24

from pylogix.lgx_device import Device

25

```

26

27

## Basic Usage

28

29

```python

30

from pylogix import PLC

31

32

# Basic read/write operations

33

with PLC() as comm:

34

comm.IPAddress = '192.168.1.100'

35

36

# Read a single tag

37

response = comm.Read('MyTagName')

38

print(f"Tag: {response.TagName}, Value: {response.Value}, Status: {response.Status}")

39

40

# Write a value to a tag

41

response = comm.Write('OutputTag', 42)

42

if response.Status == 'Success':

43

print("Write successful")

44

45

# Read multiple tags

46

tags = ['Tag1', 'Tag2', 'Tag3']

47

responses = comm.Read(tags)

48

for resp in responses:

49

print(f"{resp.TagName}: {resp.Value}")

50

51

# Manual connection management

52

comm = PLC()

53

comm.IPAddress = '192.168.1.100'

54

comm.ProcessorSlot = 0 # Default slot

55

response = comm.Read('MyTag')

56

comm.Close() # Always close when done

57

```

58

59

## Architecture

60

61

PyLogix follows a layered architecture designed for reliability and ease of use:

62

63

- **PLC Class**: High-level interface providing read/write operations and device management

64

- **Connection Layer**: Handles Ethernet I/P communication, connection pooling, and error recovery

65

- **CIP Protocol Layer**: Implements Common Industrial Protocol (CIP) for Rockwell devices

66

- **Response System**: Structured response objects with status codes and error handling

67

- **Tag Management**: Automatic data type discovery, UDT handling, and tag metadata caching

68

69

The library supports both connected and unconnected messaging, automatic data type detection, and handles complex scenarios like bit manipulation, array operations, and User Defined Types (UDTs).

70

71

## Capabilities

72

73

### Core Tag Operations

74

75

Essential read and write operations for PLC tags, supporting individual tags, arrays, and batch operations. Includes automatic data type detection and conversion.

76

77

```python { .api }

78

def Read(tag, count=1, datatype=None):

79

"""

80

Read tag values from the PLC.

81

82

Args:

83

tag (str or list): Tag name(s) to read

84

count (int): Number of elements for array reads

85

datatype (int, optional): Force specific data type

86

87

Returns:

88

Response or list[Response]: Read results

89

"""

90

91

def Write(tag, value=None, datatype=None):

92

"""

93

Write values to PLC tags.

94

95

Args:

96

tag (str or list): Tag name(s) to write

97

value: Value(s) to write

98

datatype (int, optional): Force specific data type

99

100

Returns:

101

Response or list[Response]: Write results

102

"""

103

```

104

105

[Core Operations](./core-operations.md)

106

107

### PLC Time Management

108

109

Functions for getting and setting the PLC's internal clock, useful for time synchronization and timestamp operations.

110

111

```python { .api }

112

def GetPLCTime(raw=False):

113

"""

114

Get the PLC's current time.

115

116

Args:

117

raw (bool): Return raw microseconds if True, datetime if False

118

119

Returns:

120

Response: PLC time information

121

"""

122

123

def SetPLCTime(dst=None):

124

"""

125

Set the PLC's clock to current system time.

126

127

Args:

128

dst (bool, optional): Daylight saving time flag

129

130

Returns:

131

Response: Set time operation result

132

"""

133

```

134

135

[Time Operations](./time-operations.md)

136

137

### Tag Discovery and Introspection

138

139

Capabilities for discovering available tags, programs, and retrieving tag metadata including data types and structure information.

140

141

```python { .api }

142

def GetTagList(allTags=True):

143

"""

144

Retrieve the complete tag list from the PLC.

145

146

Args:

147

allTags (bool): Include program tags if True, controller only if False

148

149

Returns:

150

Response: List of Tag objects with metadata

151

"""

152

153

def GetProgramTagList(programName):

154

"""

155

Get tags for a specific program.

156

157

Args:

158

programName (str): Program name (e.g., "Program:MainProgram")

159

160

Returns:

161

Response: List of program-specific Tag objects

162

"""

163

164

def GetProgramsList():

165

"""

166

Get list of available programs in the PLC.

167

168

Returns:

169

Response: List of program names

170

"""

171

```

172

173

[Tag Discovery](./tag-discovery.md)

174

175

### Device Discovery and Information

176

177

Network device discovery and device property retrieval for system diagnostics and configuration.

178

179

```python { .api }

180

def Discover():

181

"""

182

Discover Ethernet I/P devices on the network.

183

184

Returns:

185

Response: List of Device objects with device information

186

"""

187

188

def GetDeviceProperties():

189

"""

190

Get properties of the connected device.

191

192

Returns:

193

Response: Device object with detailed properties

194

"""

195

196

def GetModuleProperties(slot):

197

"""

198

Get properties of a module in a specific slot.

199

200

Args:

201

slot (int): Module slot number

202

203

Returns:

204

Response: Device object for the module

205

"""

206

```

207

208

[Device Discovery](./device-discovery.md)

209

210

### Advanced Messaging

211

212

Low-level CIP messaging capabilities for custom communication and advanced PLC interactions.

213

214

```python { .api }

215

def Message(cip_service, cip_class, cip_instance, cip_attribute=None, data=b''):

216

"""

217

Send custom CIP message to the PLC.

218

219

Args:

220

cip_service (int): CIP service code

221

cip_class (int): CIP class code

222

cip_instance (int): CIP instance number

223

cip_attribute (int, optional): CIP attribute number

224

data (bytes): Message data payload

225

226

Returns:

227

Response: Raw response from PLC

228

"""

229

230

def ReceiveMessage(ip_address, callback):

231

"""

232

Listen for incoming CIP messages.

233

234

Args:

235

ip_address (str): IP address to listen on

236

callback (function): Callback function for received messages

237

238

Returns:

239

Response: Listener status

240

"""

241

```

242

243

[Advanced Messaging](./advanced-messaging.md)

244

245

## Connection Configuration

246

247

```python { .api }

248

class PLC:

249

def __init__(ip_address="", slot=0, timeout=5.0, Micro800=False, port=44818):

250

"""

251

Initialize PLC connection.

252

253

Args:

254

ip_address (str): PLC IP address

255

slot (int): Processor slot number (default 0)

256

timeout (float): Socket timeout in seconds

257

Micro800 (bool): True for Micro800 series PLCs

258

port (int): Communication port (default 44818)

259

"""

260

261

# Properties

262

IPAddress: str # PLC IP address

263

Port: int # Communication port

264

ProcessorSlot: int # Processor slot

265

SocketTimeout: float # Socket timeout

266

Micro800: bool # Micro800 flag

267

Route: object # Routing configuration

268

269

@property

270

def ConnectionSize(self) -> int:

271

"""

272

Connection packet size for Forward Open requests.

273

274

Default behavior attempts Large Forward Open (508 bytes) followed by

275

Small Forward Open if the first fails. For Explicit (Unconnected)

276

sessions, uses a sensible default size.

277

278

Returns:

279

int: Connection size in bytes (default: 508)

280

"""

281

282

@ConnectionSize.setter

283

def ConnectionSize(self, connection_size: int):

284

"""

285

Set the connection packet size.

286

287

Args:

288

connection_size (int): Desired packet size in bytes

289

"""

290

```

291

292

## Response Objects

293

294

All PLC operations return Response objects containing the results and status information.

295

296

```python { .api }

297

class Response:

298

def __init__(self, tag_name, value, status):

299

"""

300

Response object for PLC operations.

301

302

Args:

303

tag_name (str): Tag name associated with the operation

304

value: Returned value or data

305

status (str or int): Operation status (string or CIP error code)

306

"""

307

308

TagName: str # Tag name associated with the operation

309

Value: any # Operation result value (tag data, lists, objects, etc.)

310

Status: str # Operation status ("Success" or descriptive error message)

311

312

@staticmethod

313

def get_error_code(status) -> str:

314

"""

315

Convert CIP error code to descriptive error message.

316

317

Args:

318

status: CIP error code (int) or error message (str)

319

320

Returns:

321

str: Descriptive error message

322

"""

323

```

324

325

## Data Types and Structures

326

327

```python { .api }

328

class Tag:

329

"""Tag metadata object representing a PLC tag with all its properties."""

330

TagName: str # Tag name

331

InstanceID: int # Instance identifier

332

SymbolType: int # Symbol type code

333

DataTypeValue: int # Data type value

334

DataType: str # Human-readable data type

335

Array: int # Array flag (0=not array, >0=array)

336

Struct: int # Structure flag (0=not struct, 1=struct)

337

Size: int # Tag size for arrays

338

AccessRight: int # Access rights

339

Internal: bool # Internal flag

340

Meta: object # Metadata information

341

Scope0: object # Scope level 0

342

Scope1: object # Scope level 1

343

Bytes: bytes # Raw byte data

344

345

@staticmethod

346

def in_filter(tag: str) -> bool:

347

"""

348

Check if the provided tag is in the filter list.

349

350

Args:

351

tag (str): Tag name to check

352

353

Returns:

354

bool: True if tag should be filtered out

355

"""

356

357

@staticmethod

358

def parse(packet: bytes, program_name: str) -> 'Tag':

359

"""

360

Parse a tag from raw packet data.

361

362

Args:

363

packet (bytes): Raw packet data from PLC

364

program_name (str): Program name for scoping

365

366

Returns:

367

Tag: Parsed tag object

368

"""

369

370

class UDT:

371

"""User Defined Type structure."""

372

Type: int # UDT type identifier

373

Name: str # UDT name

374

Fields: list[Tag] # List of field Tag objects

375

FieldsByName: dict[str, Tag] # Dictionary mapping field names to Tags

376

377

class Device:

378

"""Network device information."""

379

Length: int # Packet length

380

EncapsulationVersion: int # Encapsulation version

381

IPAddress: str # Device IP address

382

VendorID: int # Vendor identifier

383

Vendor: str # Vendor name

384

DeviceID: int # Device identifier

385

DeviceType: str # Device type description

386

ProductCode: int # Product code

387

ProductName: str # Product name

388

Revision: str # Device revision

389

Status: int # Device status

390

SerialNumber: str # Serial number (hex format)

391

ProductNameLength: int # Length of product name

392

State: int # Device state

393

394

@staticmethod

395

def get_device(device_id: int) -> str:

396

"""

397

Get device type description from device ID.

398

399

Args:

400

device_id (int): Device ID code

401

402

Returns:

403

str: Device type description or "Unknown"

404

"""

405

406

@staticmethod

407

def get_vendor(vendor_id: int) -> str:

408

"""

409

Get vendor name from vendor ID.

410

411

Args:

412

vendor_id (int): Vendor ID code

413

414

Returns:

415

str: Vendor name or "Unknown"

416

"""

417

418

@staticmethod

419

def parse(data: bytes, ip_address: str = None) -> 'Device':

420

"""

421

Parse a device from raw packet data.

422

423

Args:

424

data (bytes): Raw packet data

425

ip_address (str, optional): Override IP address

426

427

Returns:

428

Device: Parsed device object

429

"""

430

```

431

432

## Error Handling

433

434

PyLogix uses structured error handling through Response objects. The Status field contains either "Success" or a descriptive error message. Error codes are automatically converted from CIP (Common Industrial Protocol) status codes to human-readable messages.

435

436

### Complete CIP Error Code Mapping

437

438

```python

439

# CIP Error Codes (hex: description)

440

0x00: 'Success'

441

0x01: 'Connection failure'

442

0x02: 'Resource unavailable'

443

0x03: 'Invalid parameter value'

444

0x04: 'Path segment error'

445

0x05: 'Path destination unknown'

446

0x06: 'Partial transfer'

447

0x07: 'Connection lost'

448

0x08: 'Service not supported'

449

0x09: 'Invalid Attribute'

450

0x0A: 'Attribute list error'

451

0x0B: 'Already in requested mode/state'

452

0x0C: 'Object state conflict'

453

0x0D: 'Object already exists'

454

0x0E: 'Attribute not settable'

455

0x0F: 'Privilege violation'

456

0x10: 'Device state conflict'

457

0x11: 'Reply data too large'

458

0x12: 'Fragmentation of a primitive value'

459

0x13: 'Not enough data'

460

0x14: 'Attribute not supported'

461

0x15: 'Too much data'

462

0x16: 'Object does not exist'

463

0x17: 'Service fragmentation sequence not in progress'

464

0x18: 'No stored attribute data'

465

0x19: 'Store operation failure'

466

0x1A: 'Routing failure, request packet too large'

467

0x1B: 'Routing failure, response packet too large'

468

0x1C: 'Missing attribute list entry data'

469

0x1D: 'Invalid attribute value list'

470

0x1E: 'Embedded service error'

471

0x1F: 'Vendor specific'

472

0x20: 'Invalid Parameter'

473

0x21: 'Write once value or medium already written'

474

0x22: 'Invalid reply received'

475

0x23: 'Buffer overflow'

476

0x24: 'Invalid message format'

477

0x25: 'Key failure in path'

478

0x26: 'Path size invalid'

479

0x27: 'Unexpected attribute in list'

480

0x28: 'Invalid member ID'

481

0x29: 'Member not settable'

482

0x2A: 'Group 2 only server general failure'

483

0x2B: 'Unknown Modbus error'

484

0x2C: 'Attribute not gettable'

485

```

486

487

### Common Error Scenarios

488

489

```python

490

from pylogix import PLC

491

492

with PLC() as comm:

493

comm.IPAddress = '192.168.1.100'

494

495

# Handle connection errors

496

response = comm.Read('MyTag')

497

if response.Status == 'Success':

498

print(f"Value: {response.Value}")

499

elif response.Status == 'Connection failure':

500

print("Could not connect to PLC - check IP address and network")

501

elif response.Status == 'Path destination unknown':

502

print("Invalid tag name or PLC path")

503

elif response.Status == 'Object does not exist':

504

print("Tag not found in PLC")

505

else:

506

print(f"Unexpected error: {response.Status}")

507

```