OpenPLC with Python FB

In this article, you will learn how to use Python FB in OpenPLC Editor and send the PLC data to the ThingsBOard's Cloud Dashboard.

OpenPLC with Python FB- Sending PLC Data to the Cloud


What This Project Does

In this project, we use OpenPLC Runtime v4 running on a laptop (or edge device) to:

  • Generate a simulated sine wave temperature value using the built-in OpenPLC simulator

  • Read it inside a Python Function Block via shared memory

  • Send live telemetry to ThingsBoard Cloud via HTTP β€” using only Python's standard library

  • Write a connection status back to the PLC so the ST program knows if the cloud is reachable

No hardware required. No third-party packages. No cost.

Watch Full Walkthrough with LIVE Demo


System Architecture


What is a Python Function Block?

Python Function Blocks let you write automation logic in Python while integrating seamlessly with your IEC 61131-3 program. They are ideal for tasks that are difficult or verbose in Structured Text:

  • HTTP / REST API calls

  • JSON formatting and parsing

  • Statistical calculations

  • Cloud and IoT communication

Aspect
Standard IEC Function Block
Python Function Block

Execution

Runs inside the PLC scan cycle

Runs as a separate process

Timing

Synchronized with scan cycle

Asynchronous ~100ms loop

State

Managed by the runtime

Managed by the Python process

Language

ST, LD, FBD, IL

Python 3

Libraries

IEC standard functions only

Python standard library


The Two Required Functions

Every Python Function Block defines exactly two functions called automatically by the runtime:

block_init() - Called once when the Python process starts. Use it for:

  • Initializing global variables

  • Setting up timers and data structures

  • Printing startup messages

block_loop() - Called every ~100ms for the lifetime of the process. Use it for:

  • Reading inputs from shm_in

  • Processing data

  • Writing outputs to shm_out

shm_in and shm_out are injected automatically by the runtime β€” you never declare them yourself. Your IDE may show a warning β€” this is safe to ignore.


How Variables Work in Python FBs

Variables declared in the Variables Table in the OpenPLC Editor are accessible directly by name inside your Python code.

Variables declared as Input are written by the PLC and read by Python. Variables declared as Output are written by Python and read by the PLC.


Example 1: Console Print (shm_in Only)

This example introduces shm_in and struct.unpack, reading a value from the PLC into Python and printing it to the PLC Logs.

Main ST Program: Example 1

Variable Table

Main ST Program

Understanding the Sine Wave Generator

The SIN() function uses radians. One full circle = 2Ο€ = 6.283 radians. Resetting angle After 6.283, the wave repeats cleanly.

Each scan adds 0.05 radians β€” completing a full cycle in approximately 125 scans (~2.5 seconds at 20ms scan time).

The formula 50.0 + (30.0 * SIN(angle)) produces:

SIN value
Temperature

+1 (peak)

80Β°C

0 (midpoint)

50Β°C

-1 (trough)

20Β°C

Python FB Code: Example_1

Variable Table

Python Code

PLC Logs Output


Example 2: ThingsBoard Cloud Integration

This example extends Example 1 with two additions:

  • Sends the temperature to ThingsBoard Cloud via HTTP every 5 seconds

  • Write a connection status back to the PLC via shm_out - 1 for connected, 0 for disconnected

Variable Table

ThingsBoard Cloud Setup

  1. Sign up for free at thingsboard.cloud

  2. Create a new device e.g. OpenPLC

  3. Copy the url with the Access Token from the device credentials

  4. Replace YOUR_TOKEN in the code below

The ThingsBoard HTTP telemetry API endpoint is:

Python FB Code

Main ST Program

Variable Table

Main ST Program


Key Gotchas: Lessons Learned

Building this project revealed several non-obvious behaviors worth knowing before you start:

1. Use time.time() for intervals β€” not loop counters

Using loop_counter % 50 == 0 seems logical, but fires immediately on loop 0, before the runtime has stabilized. An HTTP call at that moment can stall the process. Use time.time() instead β€” it waits a true interval from a stable starting point.

2. Always import time

The OpenPLC runtime uses the time module internally to manage block_loop() timing. Even if your code does not use time directly β€” always include it, or you will get a NameError that crashes the process.

3. Declare ALL persistent variables as global in BOTH functions

Without global in block_loop() Python creates a silent local copy of the variable that is destroyed at the end of each call. Always declare in both block_init() and block_loop():

4. Avoid special characters in comments

Em dashes β€”, curly quotes ', and other Unicode characters cause C compiler errors when OpenPLC embeds your Python code. Use plain ASCII only β€” hyphens - and straight quotes '.

5. ThingsBoard Cloud requires HTTPS

Local ThingsBoard uses http:// on port 8080. ThingsBoard Cloud requires https:// on port 443.


When to Use Python vs ST vs C++

Task
Language

Cloud communication, HTTP, REST APIs

Python FB

JSON formatting, string processing

Python FB

Real-time control, timing, interlocks

Structured Text

Scan-cycle-critical logic

Structured Text

Direct hardware access, byte manipulation

C++ FB


Hardware and Software Used

Component
Details

PLC Runtime

OpenPLC Runtime v4

Editor

Autonomy Edge IDE (edge.autonomylogic.com)

Hardware

Any laptop or edge device

Cloud Dashboard

ThingsBoard Cloud (free tier)

Protocol

HTTP REST API via Python urllib

Languages

IEC 61131-3 Structured Text + Python 3


Keynotes

πŸ”— Resources


β™₯️ Work With Me

I regularly test industrial automation and IIoT devices. If you’d like me to review your product or showcase it in my courses and YouTube channel:

πŸ“§ Email: [email protected] or drop me a message on LinkedIn

Last updated