# Code and Compile Wiki

This wiki has all the content required to practice our courses.

## Welcome aboard!

This wiki from Code and Compile provides all the documentation you need if you are enrolled in the [Code and Compile E-Learning school](http://learn.codeandcompile.com).&#x20;

💡 This is a beta version. Information stored in Wiki is published from **Code and Compile,** which may have errors. Feel free to 📧 us at <info@codeandcompile.com> for any corrections.

{% tabs %}
{% tab title="E-Learning Platform" %}
📹Check out our [Code and Compile E-Learning school](http://learn.codeandcompile.com) for 12+ courses related to Industrial Automation and IIoT. Use the coupon code **GETITALL20** to get **20% off** on all Standalone courses, bundles, and yearly subscriptions.

### 🕵️‍♂️Wondering where to start?&#x20;

Check out this [free guide](https://codeandcompile.com/learning-path), which outlines the learning path to our course.s
{% endtab %}

{% tab title="YouTube" %}
Looking for some free content 👩‍💻? Check out our [YouTube](https://www.youtube.com/thegeterrdone) channel with 300+ free videos on PLC, HMI, Factory Automation, SCADA, IIoT, etc.&#x20;

If you speak or understand Hindi, then check out this [YouTube channel](https://www.youtube.com/learnplcinhindi) where you will find 100+ PLC videos on Delta Electronics.&#x20;
{% endtab %}

{% tab title="Memes" %}
Do you love memes 😍? You can explore many automation memes on our [Instagram account](https://www.instagram.com/codencompile).
{% endtab %}
{% endtabs %}

## **What will you find here?**

This wiki aims to serve as a comprehensive resource, providing a one-stop platform to support your journey into Industrial Automation and IIoT.&#x20;

:information\_source: Check out the topics on the side tree to get started!


# Meet the Creator

Started teaching since 2010

{% hint style="info" %}
**Work philosophy:** If you are not enjoying your work, you will not enjoy your life either.
{% endhint %}

## ![](/files/uqVcKrby1hxU1IWnfRbF)

## Rajvir Singh

👋 Founder of [Code and Compile ](https://www.codeandcompile.com)

👶🏼 1988: Born in **New Delhi (India)**

👨🏼‍🎓2008: Completed **Mechatronics and Industrial Automation** Diploma from **Indo-Swiss Training Center, CSIO, Chandigarh**

📽️ 2008: Started [YouTube Channel](http://www.youtube.com/thegeterrdone) on **Industrial Automation and IIoT**

👨🏼‍🎓 2009: Graduated with **Bachelor's in Instrumentation** from IET Bhaddhal

🏨 2010: Co-founder of **NFI- Industrial Automation Training Academy** in India

🇩🇪 2015: Moved to **Germany**

👨🏼‍🎓 2017: Post Graduate with **Master's in Mechatronics** from Siegen University, Germany

👨🏻‍💻 2017: Working as a **Development Engineer** in Christiani, Germany

📽️ 2017: Started another [YouTube Channel](http://www.youtube.com/learnplcinhindi) to provide **free PLC lessons in Hindi**

💻 2018: Started [**Code and Compile**](http://www.codeandcompile.com) with new ideas, passion, and Enthusiasm

📽️ 2022: Started doing a **product review** for Hardware/Software related to **IIoT and Automation**

👨🏻‍💻 2022: [**Influencer** ](https://apps.boschrexroth.com/microsites/ctrlx-automation/en/ctrlx-developr/influencer/)for **ctrlX AUTOMATION (Bosch Rexroth)**

👨🏻‍💻 2023: **Influencer** for [**LearnWorlds**](https://www.youtube.com/redirect?event=video_description\&redir_token=QUFFLUhqbmMxRXcyZGc5MEhwQmxrcnpNcGxrTFY5MWxQUXxBQ3Jtc0tsYWMyMUV1MVZhLXdtUFpob1ZlNGJwQnJobTZyeWxlOTJhMFJfZHRZZzROTjBUeWhuc3cxMHdmZTBVS3J0VmlWMUVqT3RtLW90STVjaUE3dm13SkY3OU9MRk1PSXJJbHBJaFZEeHhjMndiQjI2UnA4aw\&q=https%3A%2F%2Flearnworlds.grsm.io%2Fcodeandcompile7995\&v=RfJ2vOxczqc)**, started working as Content Creator for SIMUMATIK**

👨🏻‍💻 2025: **Working as a Content Creator for Tech products/software**

*The journey includes many challenges, rejections, and denials that you can imagine, but a passion backs it for making learning easy and fun. That has always been my goal.* 🎯

### Enough nerdy stuff

Besides being a nerd, I love:

* Traveling and Spirituality 🌍
* Mixing Music 🥳 <https://www.djcosmicray.com>
* Being in nature 🏞️ 🗻

### You can follow me at:

📸 [Instagram](https://www.instagram.com/codencompile/) 💻 [LinkedIn](https://www.linkedin.com/in/singhrajvir/)&#x20;

💡 If you like to work or collaborate with me, feel free to 📩 at **<rajvi@codeandcompile.com>**


# Get my courses - 20% OFF

Get 20% off on all the Automation and IIoT-related courses with the coupon code 'WIKI'

[Code and Compile](https://www.codeandcompile.com) offers various courses related to **PLC, HMI, SCADA, AC Drives, Factory Automation, Dashboard, Node-RED, OPC UA, MQTT, MySQL**, and Cloud interfacing.

{% embed url="<https://www.codeandcompile.com>" %}
**Code and Compile E-Learning platform**
{% endembed %}

{% embed url="<https://www.youtube.com/watch?v=-6PfamaP2Vk>" %}
Code and Compile Yearly Subscription
{% endembed %}

## Best-selling Online Courses

Use the coupon code '**WIKI**' to get 20% off on the original course price.

<table><thead><tr><th width="338.8388141584533">Course</th><th width="129.23206718799256" align="center">Original Price</th><th align="center">Discounted price</th></tr></thead><tbody><tr><td>Node-RED made Easy</td><td align="center">49€</td><td align="center">41€</td></tr><tr><td>Learn OPC UA with Node-RED</td><td align="center">39€</td><td align="center">33€</td></tr><tr><td>Interface MySQL with PLC via Node-RED</td><td align="center">49€</td><td align="center">41€</td></tr><tr><td>Learn MQTT with Node-RED</td><td align="center">49€</td><td align="center">41€</td></tr><tr><td>Learn S7-1200 PLC and HMI (Basic) </td><td align="center">49€</td><td align="center">41€</td></tr><tr><td>Learn S7-1200 PLC and HMI (Advanced)</td><td align="center">49€</td><td align="center">41€</td></tr><tr><td>Learn SCADA with Ignition and S7-1200</td><td align="center">29€</td><td align="center">24€</td></tr><tr><td>Delta PLC, HMI, VFD and Servo</td><td align="center">49€</td><td align="center">41€</td></tr><tr><td>Bundle: Master your Node-RED Programming<br>(Node-RED made Easy + JavaScript Essentials for Node-RED) </td><td align="center">79€</td><td align="center">63€</td></tr><tr><td>Bundle: Siemens<br>(S7-1200 Basic + Advanced + SCADA)</td><td align="center">99€</td><td align="center"> 89€</td></tr><tr><td>Bundle: IIoT<br>(Node-RED, OPC UA, MySQL &#x26; MQTT)</td><td align="center">119€</td><td align="center">107€</td></tr><tr><td>Bundle: Delta and IIoT<br>(Delta Industrial Automation Module + IIoT Bundle)</td><td align="center">149€</td><td align="center">119€</td></tr><tr><td>Bundle: Micro850 PLC and IIoT<br>(Micro850 PLC and IIoT + IIoT Bundle)</td><td align="center">149</td><td align="center">119€</td></tr><tr><td>Bundle: Siemens and IIoT</td><td align="center">179</td><td align="center">143€</td></tr><tr><td>Bundle: Code and Compile PRO</td><td align="center">249€</td><td align="center">199€</td></tr><tr><td>Yearly subscription (PRO)<br>Bundle of 12 courses</td><td align="center">99€</td><td align="center"> <strong>79€</strong></td></tr></tbody></table>

## How to get the discount&#x20;

{% hint style="success" %}

#### Use the coupon 'WIKI' while checking out to get 20% off on the original price

{% endhint %}

💳 For other means of payment like Western Union, money, bank transfer, kindly contact <info@codeandcompile.com>


# Smart Devices


# Pixsys TC620 Edge HMI

Your companion guide to the Pixsys TC620 deep-dive: the full software stack, the live-demo architecture, source code, and every step to rebuild one panel that replaces your HMI, PLC, and edge gateway.

## Everybody thinks this is "just an HMI." They're wrong. 🏭⚡

Most people look at an industrial touchscreen and see a pretty panel that shows some numbers on a factory wall. The **Pixsys TC620** is something else entirely: a full edge computer that happens to have a touchscreen. In this build, one box runs **real PLC logic, containerized apps, and cloud connectivity — all at the same time**, live on my desk.

This article is your companion guide to the full video. Here you'll find the complete software stack, the live-demo architecture, the source code, and every step you need to rebuild this on your own bench. 👇

## 🎥 The Full Video

{% embed url="<https://www.youtube.com/watch?v=pW4mxYZa9w4>" %}

## Why the TC620 Is Not "Just an HMI"

On this hardware, the HMI and the PLC are **not two separate boxes wired to each other — they live in the same box**. The CODESYS runtime runs right on the panel. That single fact is the whole story, and everything else in this build flows from it.

Here's what's actually inside:

{% hint style="info" %}
**Compute:** Rockchip **RK3588** — 4× Cortex-A76 @ 2.4 GHz, 64-bit ARMv8, **32 GB eMMC**, **4 GB RAM**. This is an 8-core edge computer, not a microcontroller driving a display.

**Note on chip options:** Pixsys offers the TC620 with an optional, older **RK3399** on some SKUs (no NPU). The unit in this video is the **RK3588** — that's the one you want if edge AI is anywhere on your roadmap.
{% endhint %}

The rest of the hardware that matters:

* **Display:** 12.1″, 1280×800, capacitive multi-touch, 16.7M colors, 400 cd/m² — bright enough for the real shop floor, not just the lab.
* **Two Ethernet ports** — one full Gigabit, one 10/100. This dual-port setup lets you **separate two networks** (more on why that matters below).
* **Fieldbus support:** RS485, CANopen, EtherCAT, PROFINET, EtherNet/IP — connect directly to shop-floor equipment.
* **Built-in UPS + real-time clock with battery backup** — a power loss won't corrupt your files; the device restores cleanly.
* **IP65-rated front panel**, aluminium frame — you can wash it down and it won't care.

## The Software Stack 🧱

This is where it gets interesting. The TC620 is a **Linux device with a PLC runtime plus a container engine, all in one panel**. Here's the full stack, bottom to top:

{% hint style="success" %}
**Yocto Linux** (embedded OS)

→ **CODESYS 3.5 runtime** (TargetVisu + WebVisu, OPC UA server)

→ **Podman** container engine (Docker-compatible)

→ **Node-RED** + **Grafana** (each in its own container)

→ **Pixsys Web Portal** (device config + remote assistance)
{% endhint %}

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2Fu2UH2piDxAfR2gEgPjZh%2FPixsys.mp4?alt=media&token=a4624ff7-b716-40b2-960e-9667c4dfd0b6>" %}

A few things worth calling out:

* **Podman under the hood, Docker-compatible on top.** Your existing Docker images just work — you pull `docker.io` images straight from the UI — but it's rootless Podman running them. Keep your commands consistent: use `podman`, not `docker`, when you go to the terminal, or you'll hit stuck container states.
* **CODESYS comes pre-installed.** You don't install the runtime yourself; it ships on the panel. You just start/stop it — from the IDE, or straight from the Pixsys web portal.
* **The Pixsys Web Portal** is the control center: reboot, firmware updates, network config, VNC toggle, container management, a terminal, and a CODESYS start/stop tab — all from a browser.

## The Live Demo: Vibration Monitoring Pipeline 📈

On standard hardware this would be several boxes: a PLC, an edge device, a gateway. Here it's **one box doing everything**. This is the exact data flow from the video:

{% hint style="info" %}
**Balluff SmartLight + condition-monitoring sensor** → **IO-Link Master** → **Modbus TCP** → **TC620 (CODESYS runtime)** → **OPC UA** → **Node-RED (container)** → **MQTT** (`test.mosquitto.org`) → **Grafana (container)**
{% endhint %}

### Walking the flow:

1. A **Balluff condition-monitoring sensor** measures vibration (X/Y/Z V-RMS) and temperature, feeding an **IO-Link Master**.
2. The TC620 acts as a **Modbus TCP client**, reading the sensor data directly from the IO-Link master (which is the Modbus server) over **Ethernet port 2** — the dedicated factory network. The second Ethernet port connects the laptop for CODESYS programming, kept completely separate.
3. **CODESYS** does the logic: converts the raw registers to real values, runs the threshold check, and writes back over Modbus to **trigger the SmartLight colors** when vibration crosses the limit.
4. An **OPC UA server built inside CODESYS** exposes those variables so container apps can read them.
5. **Node-RED** (running as a Podman container) reads via OPC UA and **publishes to MQTT**.
6. **Grafana** (another container) subscribes to the broker and renders the time-series dashboard.

The result: **three independent visualization layers off one panel** — CODESYS TargetVisu/WebVisu, the Node-RED dashboard, and Grafana — displayed across tabs on a single HMI, with the CPU sitting around \~22% load. Plenty of headroom left for AI workloads.

## "Why route through Node-RED? CODESYS can publish MQTT directly." 🤔

This comes up every time, so let's address it head-on. Yes — CODESYS can publish MQTT on its own. I route through Node-RED **on purpose**, and it's only possible *because* of the TC620's containerized runtime:

* **Decoupling** — data routing lives separate from control logic. I can change where data goes without touching PLC code.
* **Multi-destination fan-out** — one incoming stream, many downstream targets, added without redeploying the PLC.
* **Access for non-PLC developers** — IT/data folks can build on top of the pipeline without ever opening the PLC project.

On standard HMI hardware you couldn't do this without adding a separate edge PC. Here it's just another container. That's the whole point.

## 🧑‍💻 Source Code & Resources

Everything you need to rebuild this is here:

{% hint style="success" %}
📦 **CODESYS project** (Modbus client, vibration logic, OPC UA server, TargetVisu/WebVisu):&#x20;

{% file src="/files/1oKzrfEzg900hZmyxijP" %}

🔴 **Node-RED flow export** (OPC UA read → MQTT publish):&#x20;

{% file src="/files/Ru5GQlkEPGuy7tAqCFRp" %}

📊 **Grafana dashboard JSON** (vibration + temperature panels):&#x20;

{% file src="/files/Uyv6qIR6jR4JohFSJFLG" %}
{% endhint %}

**Quick-reference details from the demo:**

* Pixsys web portal login: user `user` / password `123456` (change this on your unit!)
* Node-RED container port mapping: host → container `1880`
* WebVisu URL pattern: `http://<HMI-IP>/webvisu.htm`
* Device: **Pixsys TC620-A-P4-WT2** — install the device package in CODESYS to see the model under device topology.

{% hint style="warning" %}
**Container persistence gotcha:** `--restart always` alone won't survive a reboot on this setup — you also need `podman-restart.service` explicitly enabled. And for internet access on IPv4-unavailable units, set IPv6 DNS (`2001:4860:4860::8888`) so containers can pull images.
{% endhint %}

## The Verdict

So, TC620, "just an HMI"? **Not even close.** It's an edge computer, a PLC, and a gateway in one panel, and the **containerized architecture is what unlocks all of it**. If you build automation or IIoT systems, this is a category of device worth knowing about.

I'm going to keep digging into this platform — there's more coming, including a look at the `logiclab-opcua.service` layer I deliberately left out of this video. **Subscribe** so you don't miss it. 🚀

## Key notes:

{% embed url="<https://canva.link/qly0r06f65tt4mu>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# item Release Unit DIN/DOUT 24V

Learn how to configure, wire, and scale item's Release Unit for real-world intralogistics applications

### 📦 What Is a Release Unit — And Why Does Logistics Need It?

In modern intralogistics and manufacturing environments, conveyors don't just move products — they **coordinate** them. The moment you introduce multiple workstations, automated guided vehicles (AGVs), or robotic pick systems, you need a way to **control the flow of items** at precise points in the line.

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2F0Ewu3u9wtGUjxFLSwETk%2FAufzeichnung%202026-03-25%20124220.mp4?alt=media&token=8ce04296-bd58-4cc9-b43c-789aaf4a834d>" %}

Without flow control, you get:

* ❌ Collisions between products on shared conveyor sections
* ❌ Parts arriving at robotic stations before the robot is ready
* ❌ AGVs docking into a conveyor that's still running
* ❌ Overflow and jams at buffer zones

This is the **Release Unit problem**: how do you reliably stop, hold, and release individual items — without expensive custom engineering, complex wiring, or a full PLC for every conveyor segment?

***

### 💡 How does the item solve the Problem

item's modular conveyor ecosystem is built on the principle that **every component should be smart, configurable, and scalable**. The Release Unit fits directly into this philosophy.

{% embed url="<https://www.youtube.com/watch?t=4s&v=iPl5v0kU3M8>" %}

Instead of building a custom stop gate or pneumatic blocker for each station, the item gives you a **standardized, plug-and-play release mechanism** that:

* Works **standalone** with no external controller
* Chains together in **automatic dual-unit mode** for back-to-back buffering
* Integrates seamlessly into **PLC-controlled lines** via digital I/O

Whether you're running a single-station workbench or a multi-stage production line, the Release Unit slots in without requiring a redesign of your conveyor layout.

***

### 🔩 What is the item Release Unit DIN/DOUT 24V?

The **item Release Unit DIN/DOUT 24V** is a digital-I/O-based flow control device designed for item conveyor systems. It physically stops and releases workpiece carriers or products at defined points on the line.

#### Key Specs at a Glance

| Feature           | Detail                                         |
| ----------------- | ---------------------------------------------- |
| Signal Interface  | Digital IN / Digital OUT (24V)                 |
| Power Supply      | 24V DC                                         |
| Operating Modes   | Standalone, Automatic (Dual-Unit), PLC Control |
| Configuration     | Browser-based webserver (no software install)  |
| Signal Monitoring | Real-time via integrated webserver             |
| Scalability       | Single unit → full PLC integration             |

#### What Makes It Stand Out

* **🌐 Browser-based configuration** — Open the web server in any browser on the same network. No proprietary software, no drivers. Change parameters in seconds.
* **📡 Real-time signal monitoring** — Watch live I/O states directly from the webserver dashboard. Diagnose faults without a separate tool.
* **⚡ Three operating modes** — Start simple with standalone, grow into PLC control. The hardware never changes.
* **🔗 Automatic dual-unit pairing** — Two Release Units can work together natively, handling buffer-and-release logic with zero PLC involvement.

***

### 🎬 Watch the Full Tutorial

This video walks through the Release Unit from unboxing to live PLC integration — including five hands-on demo scenarios filmed on a real item conveyor setup.

{% embed url="<https://youtu.be/EBDf58LisQQ>" %}

***

### 📚 What You'll Learn in This Video

The tutorial is structured into six sections, each building on the last:

#### 1. 🧠 Introduction & Overview

* What the Release Unit is and where it fits in an intralogistics system
* The five demo scenarios covered in the video
* Hardware overview and wiring basics

#### 2. 🟢 Demo 1 — Standalone Operation

* How the Release Unit functions with **no external controller**
* Configuring behavior via the integrated web server
* Use case: simple single-station hold/release

#### 3. 🔗 Demo 2 — Automatic Dual-Unit Mode

* Pairing two Release Units for **automatic buffer logic**
* How Unit 2 signals Unit 1 to release when the station is clear
* Use case: two-position buffering with zero PLC overhead

#### 4. 🤖 Demo 3 — PLC Control Case 1

* Wiring the Release Unit to a PLC digital output
* Basic PLC-triggered release on a timed or event-based signal
* Use case: PLC-controlled single-stop station

#### 5. ⚙️ Demo 4 — PLC Control Case 2

* Advanced PLC logic with sensor feedback
* Using the Release Unit's digital output as a **"part present" signal** back to the PLC
* Use case: robotic pick integration and presence detection

#### 6. 🏭 Demo 5 — PLC Control Case 3

* Multi-unit PLC orchestration across a conveyor segment
* Coordinating stop-and-release across multiple stations
* Use case: multi-level conveyor workstations and flow rack systems

#### ⚡ Bonus — Webserver Parameter Configuration

* Live walkthrough of the browser interface
* Setting release delay, operating mode, and signal polarity
* Monitoring real-time I/O without additional tools

***

### 🌍 Real-World Applications

The Release Unit is built for the environments where precision matters most:

<table><thead><tr><th width="332.6666259765625">Application</th><th>How the Release Unit Helps</th></tr></thead><tbody><tr><td><strong>AGV Docking Stations</strong></td><td>Holds the workpiece carrier until the AGV is in position, then releases on dock confirmation</td></tr><tr><td><strong>Robotic Pick Integration</strong></td><td>Stops the carrier at the robot's pick point; signals "ready" to the robot controller</td></tr><tr><td><strong>Mobile Flow Racks / Cart Systems</strong></td><td>Controls part flow to gravity-fed racks without over-stacking</td></tr><tr><td><strong>Multi-Level Conveyor Workstations</strong></td><td>Sequences parts across multiple levels with PLC coordination</td></tr></tbody></table>

***

### 📎 Keynotes

{% embed url="<https://canva.link/pefl97ze6mr2k3a>" %}

#### item Official Resources

* 🌐 [item Product Page — Release Unit](https://www.item24.com) — Full datasheet, CAD models, and ordering info
* 📄 item Release Unit Operating Manual — Wiring diagrams, parameter tables, technical specs
* 🔧 item Engineering Guide — Conveyor Systems — System design and integration documentation

#### More insights:

* 📺 [YouTube Channel — Code and Compile](https://www.youtube.com/@codecompile) — Full tutorial library
* 💼 [LinkedIn](https://www.linkedin.com/in/singhrajvir/) — Code and Compile — Industry updates, tips, and behind-the-scenes content
* 📸 [Instagram](https://www.instagram.com/rajvir.codeandcompile/) — Code and Compile — Short-form reels and quick automation tips

### ♥️ Work With Me <a href="#love-work-with-me" id="love-work-with-me"></a>

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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Smart Weighing Indicator/Controller

In this article, you will learn about various Smart Weighing Indicator from Mettler Toledo that support various protoocls like MODBUS, MQTT, API and OPC UA.

**IND400:**

* [IND400 with MQTT](/product-reviews/smart-devices/smart-weighing-indicator-controller/ind400-with-mqtt)
* [IND400 with API](/product-reviews/smart-devices/smart-weighing-indicator-controller/ind400-with-api)

**IND360:**

* [IND360 integration with PROFINET, OPC UA and API](/product-reviews/smart-devices/smart-weighing-indicator-controller/ind360-integration-with-profinet-opc-ua-and-api)
* [IND360 integration with MQTT](/product-reviews/smart-devices/smart-weighing-indicator-controller/ind360-integration-with-mqtt)

**IND590:**

* Coming Soon

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# IND400 with MQTT

In this article, you will learn about IND400 from Mettler Toledo which is a smart weighing device that support various protoocls like MODBUS, MQTT and OPC UA to share data remotely

## Smart Weighing with MQTT- IND400 in ACTION

The **Mettler Toledo IND400** is a **smart weighing indicator** designed for industrial applications. It supports modern protocols such as **MQTT, OPC UA, and Ethernet/IP**, making it **IIoT-ready** for digital factories.

## [LIVE Demo](https://www.youtube.com/watch?v=TQSgtSBYDMo)

<figure><img src="/files/2BNIVBtKLFSeXuTuMkYF" alt=""><figcaption></figcaption></figure>

{% embed url="<https://www.youtube.com/watch?v=TQSgtSBYDMo>" %}

### Data Communication and Integration

* IND400 smart weighing indicator communicates via Modbus TCP, RTU, OpenAPI, MQTT, and OPCUA for real-time data transmission to the cloud or an MQTT broker.
* IND400 can be **connected to Node-RED** for easy **data visualization** and **real-time monitoring** of MQTT data and device status.

### Remote Control and Monitoring

1. IND400 supports **remote monitoring and control via VNC**, enabling **easy access** and **real-time observation** of weighing data and device status.
2. The scale can be **controlled remotely using MQTT and Node-RED**, allowing for **real-time data and command exchange,** including zeroing, taring, preset taring, and clearing.

### Operational Modes

IND400 can be configured to send data via **Transfer mode** or **ComOne mode**, enabling **real-time data transmission** and remote control.

### Industry-Specific Features

IND400 is ideal for **pharmaceutical industries** and **food production systems**, providing **audit trails, secure data, time synchronization, and LDAP support** for GMP environments.

## Key notes:

{% embed url="<https://www.canva.com/design/DAGv3REvTV0/5uFimJ3Us1yHAuF1JDVV4Q/view>" %}

## Resources:

The following is the code that was used in the LIVE demonstration in the video.

## Transfer Mode

{% code overflow="wrap" lineNumbers="true" %}

```javascript
// Converting String to JSON
let input = msg.payload;

// Remove extra spaces and split by lines
let lines = input.trim().split('\n');

let result = {};

for (let line of lines) {
    let [key, ...valueParts] = line.split(':');
    if (!key || valueParts.length === 0) continue;

    let value = valueParts.join(':').trim();

    switch (key.trim()) {
        case 'Kopie / Kopien insgesamt':
            result.copies = value;
            break;
        case 'Datum':
            result.date = value;
            break;
        case 'Zeit':
            result.time = value;
            break;
        case 'Brutto':
            result.brutto = value;
            break;
        case 'Netto':
            result.netto = value;
            break;
        case 'Tara':
            result.tara = value;
            break;
        case 'Waage Nr.':
            result.scale_id = value;
            break;
        default:
            result[key.trim()] = value;
    }
}

msg.payload = result;
return msg;

```

{% endcode %}

## ComOne mode

### 1. Get measurements

{% code overflow="wrap" lineNumbers="true" %}

```javascript
msg.payload = {
    "Message": {
        "Header": {
            "Version": "v1.0.0",
            "MessageType": "Request",
            "ActionCode": "Read",
            "MessageID": "1234",
            "Path": "Measurement/Weight"
        }
    }
}

return msg;
```

{% endcode %}

### 2. Zero the scale

{% code overflow="wrap" lineNumbers="true" %}

```javascript
msg.payload = {
    "Message": {
        "Header": 
        {
            "Version": "v1.0.0",
            "MessageType": "Request",
            "ActionCode": "Update",
            "MessageID": "1234",
            "Path": "Command"
        },
        "Command": 
        {
            "DeviceName": "Scale1",
            "CommandCode": "Zero"
        }
    }
}
return msg;
```

{% endcode %}

### 3. Tare the scale

{% code overflow="wrap" lineNumbers="true" %}

```javascript
msg.payload = {
    "Message": {
        "Header":
        {
            "Version": "v1.0.0",
            "MessageType": "Request",
            "ActionCode": "Update",
            "MessageID": "1234",
            "Path": "Command"
        },
        "Command":
        {
            "DeviceName": "Scale1",
            "CommandCode": "Tare"
        }
    }
}
return msg;
```

{% endcode %}

### 4. Preset Tare the scale

{% code overflow="wrap" lineNumbers="true" %}

```javascript
msg.payload = {
    "Message": {
        "Header": {
            "Version": "v1.0.0",
            "MessageType": "Request",
            "ActionCode": "Update",
            "MessageID": "1234",
            "Path": "Command"
        },
        "Command": {
            "DeviceName": "Scale1",
            "CommandCode": "PresetTare",
            "Value": 0.05,
            "Unit": "kg"
        }
    }
}
return msg;

```

{% endcode %}

### 5. Clear the scale

{% code overflow="wrap" lineNumbers="true" %}

```javascript
msg.payload = {
    "Message": {
        "Header": {
            "Version": "v1.0.0",
            "MessageType": "Request",
            "ActionCode": "Update",
            "MessageID": "1234",
            "Path": "Command"
        },
        "Command": {
            "DeviceName": "Scale1",
            "CommandCode": "Clear"
        }
    }
}
return msg;
```

{% endcode %}

## Node-RED Example Code

The Node-RED flow used in the video can be found in the GitHub repository mentioned below:

<https://github.com/Code-and-Compile/Mettler_Toledo_IND400_MQTT>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# IND400 with API

In this tutorial, we continue exploring the Mettler Toledo IND400 Smart Weighing Indicator, focusing on how to utilize the REST API and WebSocket interfaces to access real-time weighing data.

### 📺 Video Tutorial

{% embed url="<https://www.youtube.com/watch?v=mq5Ddm6YlCI>" %}

## Smart Weighing with MQTT- IND400 in ACTION

The **Mettler Toledo IND400** is a **smart weighing indicator** designed for industrial applications. It supports modern protocols such as **MQTT, OPC UA, and Ethernet/IP**, making it **IIoT-ready** for digital factories.

### 🔑 What you’ll learn

* How to log in and authenticate with the IND400 using the **REST API**
* Sending GET/POST requests to read and write data
* Understanding the difference between **REST (request/response)** and **WebSocket (real-time streaming)** communication
* Setting up a WebSocket connection to continuously receive live weighing data
* Demo: Visualizing the data in **Node-RED**

### ⚙️ Example REST API Request

```http
POST http://192.168.0.58/v1.0.0/login
Content-Type: application/json

{
  "username": "002",
  "password": "yourpassword"
}
```

**Response (with access token):**

```json
{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "expiresIn": 3600
}
```

***

### 🌐 WebSocket Example

**Global variables defined in POSTMAN:**

<figure><img src="/files/Op1FPB2PUMJVdDDQbKFJ" alt=""><figcaption></figcaption></figure>

**Connection URL:**

```
ws://192.168.0.58/v1.0.0/measurements/00000000-0401-0500-0000-00C516882663?stable=true&threshold=5&unit=kg&Authorization=Bearer YOURTOKEN
```

Once connected, the IND400 continuously streams real-time weight values.

<figure><img src="/files/eWaRjGPQIzmQSYomye3W" alt=""><figcaption></figcaption></figure>

***

### 📊 Applications

* Real-time monitoring of weighing processes
* Continuous data logging into **databases or historians**
* Feeding streaming data into **dashboards, MES, or cloud platforms**
* Seamless integration with **IIoT and Industry 4.0** architectures

## Key notes:

{% embed url="<https://www.canva.com/design/DAGxLbZ9Xc8/JmgxvzLDbsKvQ2nFcITY7g/view?utlId=hb50de73826&utm_campaign=designshare&utm_content=DAGxLbZ9Xc8&utm_medium=link2&utm_source=uniquelinks>" %}

## Node-RED Example Code

The Node-RED flow used in the video can be found in the GitHub repository mentioned below:

{% embed url="<https://github.com/Code-and-Compile/Mettler_Toledo_IND400_API>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# IND360 integration with PROFINET, OPC UA and API

The IND360 Automation Weighing Indicator from Mettler Toledo is a compact, modular, and industrial-grade weighing solution designed for machine integration, process automation, and IIoT applications.

In this video and guide, we explore how **IND360** can be seamlessly integrated with:

* **Siemens S7-1500 PLC via PROFINET**
* **Edge devices via OPC UA**
* **Modern IT/IIoT systems via REST API**

This makes IND360 a powerful choice for **filling**, **dosing**, **tank weighing**, and **in-motion weighing** applications.

### 📺 Video Tutorial

{% embed url="<https://www.youtube.com/watch?v=Wu37Kir0IRo>" %}

### 🔑 What You Will Learn in This Video

In this hands-on demo, you will learn:

* How to connect **IND360 with Siemens S7-1500 PLC** using **PROFINET**
* How to read **weight & status data** in real time
* How to send **commands** such as:
  * Zero scale
  * Tare scale
  * Preset tare
  * Clear tare
* How to integrate **IND360 with an Edge device** using **OPC UA**
* How to control and visualize IND360 using **Node-RED dashboards**
* How to achieve the same functionality using **REST API**

***

### ⚙️ Demo 1: IND360 with Siemens S7-1500 PLC (PROFINET)

<figure><img src="/files/mFf8RBPjUW4AnakbT8B1" alt=""><figcaption></figcaption></figure>

In this demo:

* IND360 communicates with **Siemens S7-1500 PLC** via **PROFINET**
* PLC reads:
  * Net weight
  * Gross weight
  * Status bits
* PLC sends commands:
  * Zero scale
  * Tare scale
  * Clear tare
* Data is visualized on **Siemens KTP400 HMI**

This setup is ideal for **machine-level automation**.

#### TIA Portal Project:

The following is the TIA Portal project used in the video.

{% file src="/files/3psHQSDa0CCcDlD2QM6K" %}

***

### 🌐 Demo 2: IND360 with OPC UA (Edge Device + Node-RED)

<figure><img src="/files/2xAoQuDQGBKfVM6co7PD" alt=""><figcaption></figcaption></figure>

In this demo:

* IND360 exposes data via **OPC UA**
* An **Edge device (reComputer)** connects as OPC UA client
* **Node-RED** is used to:
  * Read live weight values
  * Monitor scale status
  * Execute control commands
* A responsive **Node-RED Dashboard** shows:
  * Net weight
  * Gross weight
  * Tare
  * Control buttons

This architecture is perfect for **IIoT, monitoring, and dashboards**.

***

### 🌐Demo 3: IND360 with REST API

<figure><img src="/files/RjtaO7Was9TDFfCAniV1" alt=""><figcaption></figcaption></figure>

In this demo:

* IND360 is accessed using **REST API**
* Edge device sends HTTP requests to:
  * Read measurement data
  * Send scale commands
* Node-RED handles:
  * API calls
  * Logic
  * Dashboard visualization

This approach is ideal for **IT-centric systems**, **cloud integration**, and **web applications**.

***

### 📊 Why IND360 for Automation & IIoT?

* Compact and modular design
* Industrial-grade reliability
* Multiple industrial protocols
* Easy PLC & IT integration
* Native OPC UA & REST API support
* Perfect fit for edge-to-cloud architectures

***

### Node-RED Example Code <a href="#node-red-example-code" id="node-red-example-code"></a>

The Node-RED flow used in the video can be found in the GitHub repository mentioned below:

{% embed url="<https://github.com/Code-and-Compile/Mettler_Toledo_IND400_MQTT>" %}

## Key notes:

{% embed url="<https://www.canva.com/design/DAG7MP4dokE/MQMZPZt4YaA6um4lrJCE5A/view?utlId=hebd7857a29&utm_campaign=designshare&utm_content=DAG7MP4dokE&utm_medium=link2&utm_source=uniquelinks>" %}

***

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# IND360 integration with MQTT

Connect the Mettler Toledo IND360 weighing controller to MQTT and stream live weight data into Node-RED and Ignition SCADA. No OPC license. No custom driver. Just MQTT.

In this video and guide, we explore how **IND360** can be seamlessly integrated via MQTT with:

* **Node-RED:** A flow-based, low-code programming tool for wiring together hardware, APIs, and online services, ideal for rapid IIoT prototyping. \
  🔗 <https://nodered.org/docs/getting-started/local>
* **Ignition by Inductive Automation** is an industrial application platform for building SCADA, HMI, and IIoT solutions with unlimited clients and a web-based deployment model. \
  🔗 <https://inductiveautomation.com/downloads/ignition>

***

### 📺 Video Tutorial

{% embed url="<https://youtu.be/7Ml6OcBUadA>" %}

***

### 🔑 What You Will Learn in This Video

In this hands-on demo, you will learn:

* How to connect **IND360 with Node-RED and Ignition SCADA** using **MQTT**
* How to read **weight & status data** in real time
* How to send **commands** such as:
  * Zero scale
  * Tare scale
  * Preset tare
  * Clear tare
* How to log the feedback in the database

***

### Prerequisites

| Requirement           | Details                                      | Status     |
| --------------------- | -------------------------------------------- | ---------- |
| Mettler Toledo IND360 | With network access via Ethernet             | ● Required |
| MQTT Broker           | Shiftr (for testing) or Ignition Distributor | ● Required |
| Node-RED              | Installed locally or on server               | Use Case 1 |
| Ignition Gateway      | Standard edition v8.3.4+                     | Use Case 2 |
| Cirrus Link Modules   | MQTT Distributor + MQTT Engine               | Use Case 2 |

***

### 1.  MQTT Broker Setup

Before connecting the IND360, you need a running MQTT broker. For initial testing, we use **Shiftr,** an MQTT broker with a visual connection map.&#x20;

{% hint style="success" %}
For production use, Ignition's built-in broker is used.
{% endhint %}

{% stepper %}
{% step %}

### Download and install the Shiftr desktop app

Visit `https://www.shiftr.io/desktop` and install the broker locally.
{% endstep %}

{% step %}

### MQTT Broker parameters

Note the MQTT port address
{% endstep %}

{% step %}

### Verify port 1883 is open

Open PowerShell and run the commands below.

```powershell
# Verify Port is Open and Listening
netstat -ano | findstr :1883

# Find Which App Owns the Port
tasklist -ano | findstr <pid>

# Open port 1883 in Windows Firewall
New-NetFirewallRule -DisplayName "MQTT Broker" -Direction Inbound -Protocol TCP -LocalPort 1883 -Action Allow

```

{% hint style="warning" %}
**Important — Firewall**

If the IND360 cannot connect via IP address, the Windows Firewall is blocking port 1883. Run the PowerShell command above to open it.
{% endhint %}
{% endstep %}
{% endstepper %}

### 2.  Enabling MQTT on IND360

In this step, we need to enable the MQTT service on the IND360 device.

{% stepper %}
{% step %}

### Open the IND360 web interface

Navigate to `https://192.168.0.8` (replace with your IND360 IP) and login using `002`.
{% endstep %}

{% step %}

### Navigate to MQTT settings

Go to **Communication → Service** and find the MQTT section.
{% endstep %}

{% step %}

### Configure MQTT parameters

Fill in all fields as shown in the table below.

| Parameter   | Value          | Notes                             |
| ----------- | -------------- | --------------------------------- |
| Client ID   | `IND360`       | Unique identifier for this device |
| Host        | `192.168.0.24` | IP of your broker machine         |
| Port        | `1883`         | Standard MQTT port                |
| Topic       |                | Root topic prefix                 |
| Username    |                | Must match broker user            |
| Supervision | `Enabled`      | Enables keep-alive monitoring     |

{% hint style="info" %}
**Topic Structure**

The IND360 automatically appends its serial number and sub-paths to the root topic. For example: `ind360/devices/C249346600/scales/_/measurements`
{% endhint %}
{% endstep %}

{% step %}

### Click SET, then CONNECT

Status should change to **Connected**.
{% endstep %}
{% endstepper %}

***

### 3.  Testing with Shiftr

Use Shiftr's visual broker map to confirm the IND360 is publishing data before integrating with Node-RED or Ignition.

**Open the Shiftr dashboard to visualize the data flowing from the IND360 device**

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FvQCsuBulKx3R5NjHO0a4%2Fmqtt%20broker.mp4?alt=media&token=9f4b62f7-7759-4068-80fc-9d42dbfa457e>" %}

***

### Use Case 1: Node-RED Integration

Use Node-RED as a lightweight MQTT client to read live weight data and send commands to the IND360 via the Shiftr broker.

#### **Reading Weight Data**

Subscribe to the measurements topic to receive live weight data as a JSON array.

* ind360/devices/C249346600
* ind360/devices/C249346600/alarms
* ind360/devices/C249346600/scales/\_
* ind360/devices/C249346600/scales/\_/measurements

<figure><img src="/files/lamc447UeZ93zIdGpOG5" alt=""><figcaption></figcaption></figure>

```javascript
//function 21
msg.payload = msg.payload[0].gross + ' ' + msg.payload[0].uomCode;
return msg;

//function 22
msg.payload = msg.payload[0].net;
return msg;

//function 23
msg.payload = msg.payload[0].tare + ' ' + msg.payload[0].uomCode;
return msg;

```

#### Sending Commands <a href="#nodered-write" id="nodered-write"></a>

Each command follows the same pattern — an Inject node triggers a Function node that builds the payload, which is then published via an MQTT Out node.

<table><thead><tr><th width="116.3333740234375">Command</th><th width="153.333251953125">Description</th><th>Topic</th></tr></thead><tbody><tr><td>tare</td><td>Sets net weight to zero using current gross as tare offset</td><td><p><strong>Invoke:</strong></p><p><code>ind360/devices/C249346600/commands/tare/invoke</code></p><p><strong>Result:</strong><br><code>ind360/devices/C249346600/commands/tare/result</code></p></td></tr><tr><td>tare-clear</td><td>Removes the tare offset, gross equals net again</td><td><p><strong>Invoke:</strong></p><p><code>ind360/devices/C249346600/commands/tare-clear/invoke</code></p><p><strong>Result:</strong><br><code>ind360/devices/C249346600/commands/tare-clear/result</code></p></td></tr><tr><td>zero</td><td>Sets current gross weight as the new zero reference point</td><td><p><strong>Invoke:</strong></p><p><code>ind360/devices/C249346600/commands/zero/invoke</code></p><p><strong>Result:</strong><br><code>ind360/devices/C249346600/commands/zero/result</code></p></td></tr><tr><td>tare-preset</td><td>Applies a manually entered known tare value</td><td><p><strong>Invoke:</strong></p><p><code>ind360/devices/C249346600/commands/tare-preset/invoke</code></p><p><strong>Result:</strong><br><code>ind360/devices/C249346600/commands/tare-preset/result</code></p></td></tr></tbody></table>

<figure><img src="/files/TvC2xhAQQdBuYjKc4v9c" alt=""><figcaption></figcaption></figure>

**Tare Command — Function Node**

```javascript
msg.payload = {
    "$correlation": "TareTest1",   // Unique ID to track this request
    "$ttl": 42,                   // Time-to-live in seconds
    "responseTopic": null,         // Set null if no response topic needed
    "command": "tare",             // Command to execute
    "content": null               // Not required for tare
}
return msg;
```

**Clear Command — Function Node**

```javascript
msg.payload =
{
    "$correlation": "TareTest1",
    "$ttl": 42,
    "responseTopic": null,
    "command": "tare-clear",
    "content" : null
}
return msg;
```

**Zero Command — Function Node**

```javascript
msg.payload =
{
    "$correlation": "Zero-Test1",
    "$ttl": 42,
    "responseTopic": null,
    "command": "zero",
    "content" : null
}
return msg;
```

**Preset Tare Command — Function Node**

```javascript
msg.payload = {
    "$correlation": "Tare-PresetTest1",
    "$ttl": 42,
    "responseTopic": null,
    "command": "tare-preset",
    "content": {
        "value": "2.0",             // Preset tare value
        "unit": "Kg"               // Unit — must match scale config
    }
}
return msg;
```

***

### Dashboard

You can use the dashboard 2.0 to visualize your value as shown below. Feel free to use the NodeRed flow for a ready-to-use dashboard.&#x20;

<div align="left"><figure><img src="/files/MKBAbyVhPR2wwsV94z1L" alt="" width="314"><figcaption></figcaption></figure></div>

{% file src="/files/17hlvKsxADLURl6EfcRg" %}

***

### Use Case 2: Ignition Integration

Ignition acts as both the MQTT broker (via MQTT Distributor) and the subscriber (via MQTT Engine). No external broker needed.&#x20;

{% stepper %}
{% step %}

### Install Ignition

Sign up for an account, download, and install Ignition. <https://inductiveautomation.com/>
{% endstep %}

{% step %}

### Install MQTT Modules

Visit `https://inductiveautomation.com/downloads/third-party-modules/8.3.4` — Match the version to your Ignition installation.

**Install via Gateway → Platform → Modules**

<table><thead><tr><th width="175.33331298828125">Module</th><th width="437.0001220703125">Role</th><th>Port</th></tr></thead><tbody><tr><td>MQTT Distributor</td><td>Acts as the MQTT broker inside Ignition</td><td>1883</td></tr><tr><td>MQTT Engine</td><td>Subscribes and converts MQTT data to Ignition tags</td><td>—</td></tr><tr><td></td><td></td><td></td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure MQTT Distributor

**Gateway → Connections → MQTT Distributor → Settings**

Enable the distributor and verify that the port is set to `1883`.

**Create broker users**

Go to Users and create two accounts:

| Username      | Password   | Used by                                              |
| ------------- | ---------- | ---------------------------------------------------- |
| `ind360`      | `ind360`   | IND360 device                                        |
| `ignition`    | `ignition` | MQTT Engine internal connection                      |
| `nodered`     | `nodered`  | (Optional) For Node-RED to subscribe and publishdata |
| {% endstep %} |            |                                                      |

{% step %}

### Configure MQTT Engine

**Gateway → Connections → MQTT Engine → Servers → Add Server**

| Field         | Value                     |
| ------------- | ------------------------- |
| URL           | `tcp://192.168.0.24:1883` |
| Server Set    | `Default Set`             |
| Username      | `ignition`                |
| Password      | `ignition`                |
| {% endstep %} |                           |

{% step %}

### Create Custom Namespace

{% hint style="info" %}
**Why a Custom Namespace?**

MQTT Engine's default namespaces (Sparkplug B and Elecsys) expect specific structured payload formats. The IND360 publishes plain JSON — so we must create a custom namespace that tells the Engine how to parse and tag the incoming data.
{% endhint %}

**Gateway → MQTT Engine → Namespaces → Custom → Create New**

| Field                | Value           | Notes                            |
| -------------------- | --------------- | -------------------------------- |
| Namespace Name       | `IND360`        | Unique identifier                |
| MQTT Topic           | `#`             | Wildcard captures all sub-topics |
| Root Folder          | `IND360_folder` | Tag browser folder name          |
| JSON Payload         | ✅ Checked       | Auto-parses JSON into tags       |
| Create Writable Tags | ✅ Checked       | Enables writing back to device   |
| {% endstep %}        |                 |                                  |

{% step %}

### &#x20;Dashboard & Commands

Once tags appear in the Tag Browser under MQTT Engine, bind them to Vision components for live display.

<div align="center"><figure><img src="/files/XTkJUsvwx9CZr2j1Z06t" alt=""><figcaption></figcaption></figure></div>

#### Useful scripts

Below are the scripts that are used for publishing the data to the MQTT broker via buttons

**Tare Button Script**

```python
import json

# Build the tare command payload
payload = json.dumps({
    "$correlation": "IgnitionTare1",   # Unique ID to track this request
    "$ttl": 42,                        # Time-to-live in seconds
    "responseTopic": None,             # No response topic needed
    "command": "tare",                 # Command to execute on IND360
    "content": None                   # Not required for tare
})

# Publish to IND360 via Ignition MQTT Engine
system.cirruslink.engine.publish(
    "Ignition Distributor",                                     # Server name in MQTT Engine → Servers
    "ind360/devices/C249346600/commands/tare/invoke",           # Command topic
    payload.encode(),                                           # Must be bytes — .encode() converts string
    1,                                                          # QoS 1 = at least once delivery
    False                                                       # Retain = False
)
```

{% hint style="warning" %}
The payload must be byte-encoded using `.encode()`. Passing a plain string causes a silent failure; no error is shown, but the command is never published. Learn more about Python scripting here: <https://docs.chariot.io/display/CLD80/ME%3A+Python+Scripting>
{% endhint %}

**Clear Button Script**

```python
import json

# Build the tare-clear command payload
# Tare-clear resets the tare back to zero (removes the tare offset)
payload = json.dumps({
    "$correlation": "IgnitionClear1",  # Unique ID to track this request
    "$ttl": 42,                        # Time-to-live in seconds before message expires
    "responseTopic": None,             # Set to None if no response topic is needed
    "command": "tare-clear",           # The command to execute — clears the existing tare value
    "content": None                    # Additional content — not required for tare-clear command
})

# Publish the clear command to the MQTT broker via Ignition MQTT Engine
system.cirruslink.engine.publish(
    "Ignition Distributor",                                        # MQTT server name as configured in MQTT Engine > Servers
    "ind360/devices/C249346600/commands/tare-clear/invoke",        # MQTT topic — tare-clear command path for device C249346600
    payload.encode(),                                              # Payload must be bytes — .encode() converts string to bytes
    1,        
```

**Zero Button Script**

```python
import json

# Build the zero command payload as a Python dictionary
# Zero command sets the current scale reading as the new zero reference point
payload = json.dumps({
    "$correlation": "IgnitionZero1",   # Unique ID to track this request (can be any string)
    "$ttl": 42,                        # Time-to-live in seconds before message expires
    "responseTopic": None,             # Set to None if no response topic is needed
    "command": "zero",                 # The command to execute on IND360 (zero = set current weight as new zero)
    "content": None                    # Additional content — not required for zero command
})

# Publish the zero command to the MQTT broker via Ignition MQTT Engine
system.cirruslink.engine.publish(
    "Ignition Distributor",                                    # MQTT server name as configured in MQTT Engine > Servers
    "ind360/devices/C249346600/commands/zero/invoke",          # MQTT topic — device serial number C249346600 is part of the path
    payload.encode(),                                          # Payload must be bytes — .encode() converts string to bytes
    1,                                                         # QoS level 1 = at least once delivery (reliable)
    False                                                      # Retain flag — False means broker won't store this message
)
```

**Preset Tare Button Script**

* Take an input field and rename that to 'presetTare'
* Add the script below to the Preset Tare button.

```python
import json

# Read the preset value from the input field on the dashboard
preset_value = event.source.parent.getComponent("presetTare").value

if preset_value <= 0:
    system.gui.messageBox("Please enter a valid preset tare value", "Invalid Input")
else:
    payload = json.dumps({
        "$correlation": "IgnitionPresetTare1",
        "$ttl": 42,
        "responseTopic": None,
        "command": "tare-preset",
        "content": {
            "value": str(preset_value),     # Dynamic value from input field
            "unit": "Kg"
        }
    })
    system.cirruslink.engine.publish(
        "Ignition Distributor",
        "ind360/devices/C249346600/commands/tare-preset/invoke",
        payload.encode(), 1, False
    )
```

{% endstep %}

{% step %}

### Feedback Logging to Database

Log real device confirmation to SQLite using a Gateway Tag Change script triggered by the result timestamp.

**Create Database Table**

First, create a table in the default database. Run the following script in the Tools > Database Query browser.

```sql
CREATE TABLE IF NOT EXISTS ind360_command_log (
        id          INT AUTO_INCREMENT PRIMARY KEY,
        command     TEXT,
        result      TEXT,
        timestamp   TEXT
    )
```

To delete the table, use the following script

```sql
Drop table <table name>
```

**Gateway Tag Change Script:**

**tare\_result**

Watch tag: `[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare/result/_timestamp`

```python
def onTagChange(initialChange, newValue, previousValue, event, executionCount):
	
    # Get raw IND360 timestamp e.g. "2026-04-28T11:45:41.000Z"
    raw_timestamp = str(newValue.value)

    # Convert ISO 8601 format to SQLite compatible format
    # Replace the T separator with a space and remove the Z suffix
    clean_timestamp = raw_timestamp.replace("T", " ").replace("Z", "")
    # Result: "2026-04-28 11:45:41.000" ✅

    # Read result fields from MQTT Engine tags
    description = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare/result/content/description"
    ])[0].value

    code = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare/result/code"
    ])[0].value

    correlation = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare/result/_correlation"
    ])[0].value

    # Log to database with cleaned SQLite compatible timestamp
    system.db.runPrepUpdate(
        "INSERT INTO ind360_command_log (command, result, timestamp) VALUES (?, ?, ?)",
        ["tare", description, clean_timestamp],
        database="Sample_SQLite_Database"
    )
```

**clear\_result**

Watch tag: `[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/clear/result/_timestamp`

```python
def onTagChange(initialChange, newValue, previousValue, event, executionCount):
	
    # Get raw IND360 timestamp e.g. "2026-04-28T11:45:41.000Z"
    raw_timestamp = str(newValue.value)

    # Convert ISO 8601 format to SQLite compatible format
    # Replace the T separator with a space and remove the Z suffix
    clean_timestamp = raw_timestamp.replace("T", " ").replace("Z", "")
    # Result: "2026-04-28 11:45:41.000" 

    # Read result fields from MQTT Engine tags
    description = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare-clear/result/content/description"
    ])[0].value

    code = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare-clear/result/code"
    ])[0].value

    correlation = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare-clear/result/_correlation"
    ])[0].value

    # Log to database with cleaned SQLite compatible timestamp
    system.db.runPrepUpdate(
        "INSERT INTO ind360_command_log (command, result, timestamp) VALUES (?, ?, ?)",
        ["clear", description, clean_timestamp],
        database="Sample_SQLite_Database"
    )
```

**zero\_result**

Watch tag: `[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/zero/result/_timestamp`

```python
def onTagChange(initialChange, newValue, previousValue, event, executionCount):
	
    # Get raw IND360 timestamp e.g. "2026-04-28T11:45:41.000Z"
    raw_timestamp = str(newValue.value)

    # Convert ISO 8601 format to SQLite compatible format
    # Replace the T separator with a space and remove the Z suffix
    clean_timestamp = raw_timestamp.replace("T", " ").replace("Z", "")
    # Result: "2026-04-28 11:45:41.000" ✅

    # Read result fields from MQTT Engine tags
    description = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/zero/result/content/description"
    ])[0].value

    code = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/zero/result/code"
    ])[0].value

    correlation = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/zero/result/_correlation"
    ])[0].value

    # Log to database with cleaned SQLite compatible timestamp
    system.db.runPrepUpdate(
        "INSERT INTO ind360_command_log (command, result, timestamp) VALUES (?, ?, ?)",
        ["zero", description, clean_timestamp],
        database="Sample_SQLite_Database"
    )
```

**preset\_tare**

Watch tag: `[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare-preset/result/_timestamp`

```python
def onTagChange(initialChange, newValue, previousValue, event, executionCount):
	
    # Get raw IND360 timestamp e.g. "2026-04-28T11:45:41.000Z"
    raw_timestamp = str(newValue.value)

    # Convert ISO 8601 format to SQLite compatible format
    # Replace the T separator with a space and remove the Z suffix
    clean_timestamp = raw_timestamp.replace("T", " ").replace("Z", "")
    # Result: "2026-04-28 11:45:41.000" ✅

    # Read result fields from MQTT Engine tags
    description = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare-preset/result/content/description"
    ])[0].value

    code = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare-preset/result/code"
    ])[0].value

    correlation = system.tag.readBlocking([
        "[MQTT Engine]IND360_folder/ind360/devices/C249346600/commands/tare-preset/result/_correlation"
    ])[0].value

    # Log to database with cleaned SQLite compatible timestamp
    system.db.runPrepUpdate(
        "INSERT INTO ind360_command_log (command, result, timestamp) VALUES (?, ?, ?)",
        ["tare", description, clean_timestamp],
        database="Sample_SQLite_Database"
    )
```

**Table SQL Query Binding**

To visualize the feedback in the table. Add a table to your screen and bind the data with the following script

```sql
SELECT
    command   AS Command,
    result    AS Result,
    timestamp AS Timestamp
FROM ind360_command_log
ORDER BY datetime(timestamp) DESC
LIMIT 50
```

**Clear button**

To clear the values in the table, you can use the following script

```python
# Show confirmation dialog before clearing
# Prevents accidental deletion of command history
result = system.gui.confirm(
    "Are you sure you want to clear all feedback records?",
    "Clear Feedback Table"
)

# Only delete if operator clicked Yes
if result:
    system.db.runUpdateQuery(
        "DELETE FROM ind360_command_log",
        database="Sample_SQLite_Database"
    )
```

{% endstep %}
{% endstepper %}

***

### Topic Structure Reference

```python
ind360/
├── devices/C249346600/
│ ├── scales/_/measurements #subscribe
│ ├── scales/_ #subscribe
│ ├── alarms #subscribe
│ └── commands/
│ ├── tare/invoke #publish
│ ├── tare/result #subscribe
│ ├── tare-clear/invoke #publish
│ ├── tare-clear/result #subscribe
│ ├── zero/invoke #publish
│ ├── zero/result #subscribe
│ ├── tare-preset/invoke #publish
│ └── tare-preset/result #subscribe
```

### Command Payload Reference

<table><thead><tr><th width="150.3333740234375">Command</th><th width="351.333251953125">content field</th><th>Notes</th></tr></thead><tbody><tr><td><code>tare</code></td><td><code>null</code></td><td>No content needed</td></tr><tr><td><code>tare-clear</code></td><td><code>null</code></td><td>No content needed</td></tr><tr><td><code>zero</code></td><td><code>null</code></td><td>No content needed</td></tr><tr><td><code>tare-preset</code></td><td><code>{"value": "2.0", "unit": "Kg"}</code></td><td>Value and unit required</td></tr></tbody></table>

#### Ignition Project

You can import this project in your Ignition designer to use it as a prototype:

{% file src="/files/87quKNpKqKT9Bz35QqCo" %}

***

## Key notes:

{% embed url="<https://www.canva.com/design/DAG7MP4dokE/MQMZPZt4YaA6um4lrJCE5A/view?utlId=hebd7857a29&utm_campaign=designshare&utm_content=DAG7MP4dokE&utm_medium=link2&utm_source=uniquelinks>" %}

***

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# IND590 CODESYS Course

Turn the Mettler Toledo IND590 into a full soft-PLC with CODESYS. From your first login to bidirectional PLC data exchange over PROFINET, this course takes you from weighing terminal to programmable automation controller running your own IEC 61131-3 logic, HMI, and factory integrations.

The **Mettler Toledo IND590** is not just a weighing terminal, it hosts a full **CODESYS soft-PLC** runtime. That means the same box that measures your weight can also run your control logic, serve a browser-based HMI, drive its own on-device panel, and exchange custom data with any PLC on your line, no gateway box and no extra hardware.

{% embed url="<https://canva.link/i03d3nlfs2m9ssx>" %}

This course is a hands-on, build-along series that takes you from your very first login all the way to a production-grade PROFINET data exchange with a Siemens S7-1500. Every episode is practical: you build the project, deploy it to real hardware, and end up with something you can reuse on the factory floor.

{% hint style="info" %}
**Course launching soon**

The full **IND590 CODESYS course** is not public yet. It is scheduled to go live in the **first week of September**. This page is your roadmap, bookmark it and check back, or subscribe on the [Code and Compile YouTube channel](https://www.youtube.com/@CodeandCompile) to be notified the moment it drops.
{% endhint %}

***

### 🎯 Who This Course Is For

* **Automation engineers** who already own an IND590 and want to unlock its CODESYS capability instead of leaving it as a simple indicator
* **System integrators** who need the IND590 to talk to a PLC, an HMI, or a SCADA system
* **Controls developers** curious about running IEC 61131-3 logic directly on a weighing controller
* Anyone moving from **reading weight data** to **building real applications** around it

{% hint style="success" %}
No prior CODESYS experience is required. The course starts from the very first login and builds up one concept at a time.
{% endhint %}

***

### 🔑 What You Will Learn

By the end of this series you will be able to:

* Activate and configure the **CODESYS runtime** on the IND590
* Read live **weight, status, and scale data** into your own PLC program
* Build a **stateful weighing application** using Function Blocks the right way
* Design a **browser-based WebVisu HMI** and a **TargetVisu on-device panel**
* Stream weight data to **Node-RED** over raw TCP/IP, and send commands back
* Exchange **custom data** with a **Siemens S7-1500 over PROFINET** using Shared Variables
* Understand when to use **standard weighing interfaces** versus **custom PLC template mode**, and pick the right tool for each job

***

### 🛠️ Prerequisites

| Requirement                  | Details                                                                 | Status     |
| ---------------------------- | ----------------------------------------------------------------------- | ---------- |
| Mettler Toledo IND590        | With CODESYS runtime and network access via Ethernet                    | ● Required |
| CODESYS Development System   | The IDE used to write and download your logic                           | ● Required |
| CODESYS license              | Test mode, pre-installed, or a separate license (covered in the course) | ● Required |
| Web browser                  | For the WebVisu HMI and IND590 web server                               | ● Required |
| Siemens S7-1500 + TIA Portal | For the PROFINET data-exchange episodes                                 | Use Case   |
| Node-RED                     | Installed locally or on a server, for the TCP/IP integration            | Use Case   |

{% hint style="warning" %}
**Library and firmware versions must match.** The ParameterManager and Scale libraries used in the later episodes must match your IND590 firmware version, or you will hit unresolved-reference errors on download. When in doubt, update the libraries together and contact your OEM for proprietary library updates.
{% endhint %}

***

### 📚 Course Roadmap

The course builds in a deliberate order, each module assumes the one before it.

{% stepper %}
{% step %}

### Getting Started with CODESYS on the IND590

Your first login, user management, and understanding what the CODESYS license actually unlocks. You will learn the three ways to experience CODESYS on the IND590 (test mode, pre-installed, separate license), the difference between the **PLC Interface** and a **CODESYS license**, and how activation works via `activation.mt.com`.
{% endstep %}

{% step %}

### Building Your First Weighing Program

Reading live weight values into CODESYS and structuring your logic properly. The key lesson: use **Function Blocks (not Functions)** for stateful weighing operations like Tare, Zero, Preset, and Clear, because Functions re-trigger every scan and corrupt values on a filling line. You will also meet the **flag pattern**, where lower-priority tasks only set request flags and the MainTask exclusively executes state changes to avoid race conditions.
{% endstep %}

{% step %}

### WebVisu – A Browser-Based HMI

Build and style a browser-based operator screen served straight from the IND590. Live weight display, setpoint entry, button command logic, a dynamic progress bar, and a professional dark theme. You will also see how to deploy the HMI to any third-party browser or device on the network.
{% endstep %}

{% step %}

### TargetVisu – The On-Device Panel

Build the UI that runs on the IND590's own panel at its native 800×480 resolution, including handling keypad-only (non-touchscreen) hardware and the fixed F-key assignments for Clear, Preset Tare, Tare, and Zero.
{% endstep %}

{% step %}

### TCP/IP Integration with Node-RED

Stream Gross, Net, Tare, and status from the IND590 into a live **Node-RED** dashboard over raw TCP, no middleware and no broker. Then close the loop by sending Setpoint and command values back down to CODESYS. Bidirectional TCP with a weighing controller done cleanly, end to end.
{% endstep %}

{% step %}

### Shared Variables – Custom Data over PROFINET

The finale: exchange your own **custom data** with a **Siemens S7-1500 over PROFINET** using the **ParameterManager** library and **Shared Variables**, in both directions. The PLC sends down a target weight and tolerance; the IND590 weighs the part, classifies it Under / OK / Over, and sends the verdict plus live values back, all flowing straight into your Siemens tag table. Two worked examples: a bare live-coded mechanism, then a production-ready pattern you can drop onto a real line.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
Source code, presentations, and companion material for each episode will be available in the course platform once it is public.
{% endhint %}

***

## ♥️ Work With Me

I regularly test and build with **industrial automation and IIoT devices**. If you would like me to **review your product** or feature it in my courses and YouTube channel:

📧 Email: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Visual Factory elements

In this page you will find the product reviews, get access to the presentation and source code used in the video

## Visual Factory- The Future of Industrial Efficiency

* 🚦 **Visual factory** leverages **technology** and **visual devices** to enable machines to communicate instantly through **light, color, and signals** without words.
* 🔆 Devices like **WLS27 Pro light strip**, **WLF truck flexible strip light**, and **programmable tower lights** offer various modes (**run, level, segment, gauge, LED, dim and blend, demo**) to indicate machine status and process parameters.
* 🔌 The **Olink master** from Banner, an **8-port master**, can be configured using **Olink configurator** and **DXM configuration software** to read/send signals, connect to **PLCs** or **edge devices**, and program internal logic.

## LIVE Demo

{% embed url="<https://www.youtube.com/watch?t=397s&v=QKbdvSX7Pqw>" %}

### Applications and Benefits

* 📊 Visual factory devices can **simulate** machine status, **monitor** processes, **recognize** signals, and **coordinate** with operators, improving communication efficiency across the shop floor.
* 🏭 This technology can be used in various **industrial processes,** including **sensor simulation**, **process visualization**, **operator guidance**, and **loading dock communication**.
* 🔧 Visual factory systems boost **productivity**, **communication**, and **efficiency** in industrial environments by providing **real-time feedback** on **process status**, **cycle times**, and **error conditions**.

## Key notes:

{% embed url="<https://www.canva.com/design/DAGhm7U2hcA/4PqVAXE2nj4kfYK-cIOCJw/view?utlId=h12986586b8&utm_campaign=designshare&utm_content=DAGhm7U2hcA&utm_medium=link2&utm_source=uniquelinks>" %}

## Specific Devices and Features

* 💡 The **K50 Pro indicator** displays various **colors**, **animations**, and **sequences** to show process status and errors, making it suitable for use on **AGVs**, **machines**, and **robots**.
* 📺 The **SD50 status display** presents **messages**, **measurements**, and **counts** with a **white screen**, controlled using **Olink software** for flexible visual feedback.
* 🔘 The **multicolor touch button** combines **display**, **acknowledgement**, and **input** functions, showing information such as **sensor distance** and **counts** with customizable visual cues.
* 👋 The **K50 Pro with opto sensor** uses an **optical sensor** to detect hand distance, providing visual feedback through colors and animations for different industrial applications.
* 🧠 The I**O-Link master** functions as a central control unit for visual factory devices, allowing comprehensive management of **messages**, **animations**, and **sequences** across multiple devices to improve industrial communication and efficiency.

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# WAGO Compact Controller 100

Sending sensor data to Cloud made EASY

<figure><img src="/files/3l4Y7KgK5OigeLlzWnry" alt=""><figcaption></figcaption></figure>

## Compact Controller 100 features:  <a href="#el_1719235576019_635" id="el_1719235576019_635"></a>

* Cortex A7 processor with 650 MHz
* Onboard eight digital inputs, four digital outputs, two analog inputs, two analog outputs, and two temperature sensor inputs
* 2 Ethernet ports for external communication (OPC UA, MQTT, EtherNet IP, EtherCAT, Modbus TCP/IP, etc.)
* Expandable memory using an external memory card
* Programming options with CODESYS or Node-RED

## Video Review

{% embed url="<https://www.youtube.com/watch?v=SKuDOWOsVDY>" %}

#### In this video, I'll show you how to: <a href="#el_1719235531007_594" id="el_1719235531007_594"></a>

* Read raw data from various sensors
* Process the data to make it meaningful
* Sending data to the Amazon Cloud without using any extra edge device

#### Why is sending sensor data to the cloud crucial for modern industrial IoT applications? It offers real-time data access from anywhere for monitoring and control, leverages cloud computing resources for data analysis, and uses machine learning to identify patterns and predict trends.  <a href="#el_1719231835977_368" id="el_1719231835977_368"></a>

*Gone are the days of manual data recording from HMI for analytics. Today, we have smart controllers like WAGO's Compact Controller 100 (CC100), making it easy to send sensor data to the cloud.*&#x20;

## Canva Presentation

You can view the **Canva presentation** I used in the video:

{% embed url="<https://www.canva.com/design/DAGHNbnhjwY/MaHfZRF9Tq_VNey8Pjb3kw/view?utlId=h6c605d925e&utm_campaign=designshare&utm_content=DAGHNbnhjwY&utm_medium=link2&utm_source=uniquelinks>" %}

#### WAGO is a registered trademark of WAGO Verwaltungsgesellschaft mbH. <a href="#el_1710502424804_440" id="el_1710502424804_440"></a>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Analog or Digital Signal to IO-Link

In this article, you will learn how to convert analog and digital signals to IO-Link using Banner's IO-Link hubs and convertors.

## Banner IO-Link Hubs and Converters

In my new video 📹, uncover the secrets of converting digital and analog data from the shop floor to IO-Link using Banner Engineering's innovative IO-Link Hubs and Converters.

🔌 Converting data to IO-Link simplifies industrial automation, enhancing diagnostics and reducing costs. 📈 It offers flexibility, improved data accuracy, and is key for efficient IIoT systems. 🌐✨

## Video Review

{% embed url="<https://www.youtube.com/watch?v=RlrCrYMG7Cs>" %}

## Canva Presentation

You can view the **Canva presentation** I used in the video:

{% embed url="<https://www.canva.com/design/DAF2JvF_qyc/UVz3Dg7nhQ2F86W3m7vZEQ/view?utlId=h6d7fd324ff&utm_campaign=designshare&utm_content=DAF2JvF_qyc&utm_medium=link2&utm_source=uniquelinks>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Data Visualization using Peakboard

This article presents an illustrative example showing OEE data from a simulated virtual factory on the Peakboard dashboard.

## Creating dashboards feels like a serene meditation session!  <a href="#el_1690237193298_340" id="el_1690237193298_340"></a>

I'm back with my **second take on Peakboard**, and this time, it's all about showcasing my **OEE data from a Factory simulation environment** created on [**SIMUMATIK**](https://www.codeandcompile.com/simumatik). 🏭✨

## Video Example 1: OEE Dashboard

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2F30mIaiRZ4XbZPV14Oqsw%2FVisualize%20Your%20Oee%20Data%20On%20Peakboard.mp4?alt=media&token=9677666d-c84c-4a41-ad67-a8b7fcfd54f4>" %}

**Creating dashboards on Peakboard is not just a task; it's a blast!** 🔥🎉 The ready-to-use widgets make the process super fun and incredibly efficient.\
\
But wait, how did I crunch those OEE numbers? Let me break it down for you:

1. **Quality Calculation**: I'm diving into the production counts (Good and Bad parts) from my factory, all communicated by the S7-1500 PLC via OPC UA.
2. **Availability Check**: I'm considering total available time, system stop time, and run time to get the perfect metric.
3. **Performance:** It is based on ideal production time, total parts created, and system run time to gauge the performance.

**And here's the magic equation:**

{% hint style="success" %}

### OEE = Performance x Availability x Quality. <a href="#el_1701686734310_369" id="el_1701686734310_369"></a>

{% endhint %}

The fun doesn't stop there! You can seamlessly share this OEE data with 3rd party applications via MQTT, SQL, API, SAP, and more. 🔄

## Video Example 2: Real-time Data visualization

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FuZc3OyvmO5pcKO8mTmwm%2FFrom%20Factory%20To%20Smart%20Factory%20In%20No%20Time!.mp4?alt=media&token=50bff1a2-7e66-4fbf-a5c8-0b2569ff7b1c>" %}

Imagine a device that effortlessly connects with over **100 data sources**. In the illustration below, witness real-time data flowing📈 from diverse PLCs through Modbus TCP/IP, OPC UA, S7 Comm., and MQTT, all converging into the Peakboard Box. 🌐✨\
\
Additionally, we send the processed data 🚀 to the **HiveMQ MQTT broker.**\
\
**No programming skills needed!** 🎨✨ You can mold your data effortlessly using the intuitive **Block editor 🧩 or Lua scripts** 📑. And the best part 😎😍? Your creations can easily journey to the cloud for analysis via **MQTT,** opening a realm of possibilities! 🌥️📊\
\
✅If you do not have a **Peakboard box**, don't worry, you can check their **free Peakboard designer tool** at 👉 [https://peakboard.com](https://peakboard.com/)<br>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Turck TX707 HMI/PLC

This article presents an illustrative example demonstrating the capabilities of Turck TX707 HMI/PLC Series to read data via various communication protocols.

## I love bringing various devices to let them talk together <a href="#el_1690237193298_340" id="el_1690237193298_340"></a>

I've finally got my hands on the Turck TX707 HMI/PLC Series, which comes with CODESYS V3 PLC and Target WebVisu 📊.

## Illustration

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FCAd7GIgo8HmvbIRywMW0%2FUsing%20Turck%20Tx707%20Hmi-Plc%20Series%20To%20Read%20Factory%20Data.mp4?alt=media&token=730ffb6f-3abb-4f11-b231-2792f37e1201>" %}

* I tried several communication protocols, such as PROFINET, EtherCAT, and MODBUS TCP/IP, and they all worked flawlessly. It also supports **MODBUS RTU**, **CANopen**, **SAE J1939,** and **EtherNet/IP**. 🚀
* If you are looking for a powerful HMI with PLC inside to read/write the data from your shop floor, then check out this **Turck TX707**: <https://www.turck.de/en/product/100002030>
* The workflow below illustrates the possibility of reading data from various devices, including Micro850 PLC, Delta 12SE PLC, ifm-IO-Link master, and SICK Sensor Intelligence-IO-Link **master** 👩‍💻.

{% hint style="success" %}
Special thanks to ❤️:

\- [Chien-Hsun (Josh) Chuang](https://www.linkedin.com/in/chien-hsun-josh-chuang-60a02a156/) to let me play with Turck devices 👩‍💻

\- [Vikan Chirawatpongsa](https://www.linkedin.com/in/vikan-chirawatpongsa-1666785/) - To connect me with Turck 🚀<br>
{% endhint %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# IT-OT Integration using SIA Connect

This article presents an illustrative example demonstrating the possibility of sending factory data to the cloud using SIA Connect and displaying the analytics on reTerminal from Seeed Studio

## So much in love with these two devices!  <a href="#el_1690237193298_340" id="el_1690237193298_340"></a>

* [SIA Connect](https://sia-connect.com)- No code Edge gateway for IIoT & Industry 4.0&#x20;
* [reTerminal](https://www.seeedstudio.com/reTerminal-DM-p-5616.html?queryID=c5c1070a4d8e6bd12aa002eb79cd044a\&objectID=5616\&indexName=bazaar_retailer_products) from Seeed Studio - All-in-one PLC, HMI, and Edge Gateway device 👩‍

## Illustration

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2F8n5WzTiBchL20f8kDboF%2FIt-Ot%20Integration%20Using%20Sia%20Connect.mp4?alt=media&token=cb4c84b8-e307-464a-bcef-72579abda256>" %}

* In this dataflow, I am reading data from various PLCs 🏭 which support different communication protocols 🚀.
* It took me around 30 minutes to set up this workflow 📈.
* The data is displayed on the Node-RED dashboard created on reTerminal, which acts as an MQTT Broker 🌟.
* Furthermore, SIA Connect makes it extremely easy to upstream the data to the HiveMQ MQTT broker&#x20;

{% hint style="success" %}
Thanks to **Seeed Studio and SIA Connect** for introducing these devices to me ❤️
{% endhint %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Condition monitoring using SICK SIG350

This article presents an illustrative example demonstrating the measurement of temperature and vibrations using the MPB10 sensor and SIG350 from Sick Sensor Intelligence.

## IO-Link masters are getting SICK! <a href="#el_1690237193298_340" id="el_1690237193298_340"></a>

Check out SIG350 (EtherCAT version) from Sick Sensor Intelligence, which can not only send the data via EtherCAT but also supports OPC UA, API, and MQTT.&#x20;

This diagram illustrates the process of observing data from the MPB10 condition monitoring sensor on the dashboard through the utilization of EtherCAT and EoE.&#x20;

Our setup involves the implementation of the **ctrlX CORE** as an **EtherCAT** master. The data can be retrieved from the **ctrlX CORE** either through the **ctrlX Data Layer** or directly from the **SIG350** using **OPC UA** and **API** over 👉[**EoE**](https://support.sick.com/sick-knowledgebase/article/?code=KA-02982).&#x20;

## Illustration

<figure><img src="/files/qMk6NPheAGDilDBtNzJz" alt=""><figcaption></figcaption></figure>

## **Why measure Temperature and Vibration from motors?**&#x20;

* Accurate temperature and vibration measurement in motors is crucial for preventive maintenance.&#x20;
* Elevated temperatures can indicate potential failures, while abnormal vibrations signal misalignments or mechanical issues.&#x20;
* Timely detection enhances motor lifespan, minimizes downtime, and ensures operational efficiency, reducing costly repairs and production interruptions.

## Node-RED Flow

<https://github.com/Code-and-Compile/Sick_SIG350_IOLink>

<figure><img src="/files/ZmRU9dw13aM63Fj4QQ31" alt="" width="563"><figcaption></figcaption></figure>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Snap Signal- Bridge OT with IT

In this article, you will learn how to bridge OT signal with IT using DXMR90-X1- Industrial Controller

In this video, I introduce you to the Banner Snap Signal concept, which allows factory data to be captured, converted, and distributed quickly to the Cloud. This allows IT and OT Integration quite flexibly. [Learn more](https://www.bannerengineering.com/be/en/products/connectivity-technology/snap-signal.html)

### SnapSignal: OT and IT Integration

{% embed url="<https://youtu.be/8ZbsFxjKTW0>" %}

### Data Integration and Standardization

* Banner Snap Signal **converts diverse factory sensor data** into a **standardized protocol**, enabling seamless integration of operational technology (OT) with information technology (IT) for enhanced analytics and decision-making.
* The DXM configuration software allows users to **read sensor signals**, **store values in registers**, and **scale data** for meaningful interpretation, with options to add offset values for simplified programming.

### Cloud Connectivity and Analytics

* The DXM controller facilitates **cloud data transmission** using HTTP Cloud Push, configurable through the DXM software by specifying registers, cloud server details, and push intervals.
* Banner Cloud dashboard provides an **intuitive interface** for displaying and analyzing sensor data, offering **real-time updates** and **historical data views** for various parameters like humidity, temperature, and acceleration.

## 📑 Scaling Formula

$$
Y = ((Y2 - Y1)/(X2 - X1)) \*
(RAW - X1) + Y1
$$

{% hint style="warning" %}
**Y = Output**, Y1 = Output min., Y2 = Output max., X1 = Input min., X2 = Input max.
{% endhint %}

## **📊 Node-RED flow**

{% file src="/files/cOtD5yBe7k8vuI24nEmC" %}

## **📑 BOM**

**The following are the devices used in the Banner Snap Signal kit:**

* DXMR90-X1- Industrial Controller:<https://www.bannerengineering.com/th/en/products/part.812240.html>
* S15C-I-MQ 810628- 4-20mA Current to Modbus Converter:<https://www.bannerengineering.com/th/en/search.html?q=S15C-I-MQ>
* Q4XTILAF100-Q8 94885- Laser Sensor with 4-20ma Analog Output: Output:<https://www.bannerengineering.com/th/en/products/part.810628.html>&#x20;
* S15S-TH-MQ 812242- Temp/Humidity Sensor in S15 Housing: <https://www.bannerengineering.com/th/en/products/part.812242.html>
* K50PTCD4SQ 812688- K50 Pro Touch with PICK-IQ:<https://www.bannerengineering.com/th/en/products/part.812688.html>
* WLS15PXRGB0220DSSQP 809930 WLS15- Pro Strip Light with PICK-IQ:<https://www.bannerengineering.com/th/en/products/part.809930.html>
* R70SR2MQ- Wireless Transmitter and Receiver: <https://www.bannerengineering.com/th/en/products/part.812526.html>
* S15C-CT-MQ\*\*\*\*-\*\*\*\* Current Transformer:<https://www.bannerengineering.com/th/en/products/part.810627.html>
* QM30VT2-QP\*\*\*\*-\*\*\*\* Temperature and Vibration sensor:<https://www.bannerengineering.com/th/en/products/part.807969.html>
* PSW-24-1 803521- Power Supply: <https://www.bannerengineering.com/th/en/products/part.803521.html>
* CSB-M1250M1250-T 807397- Parallel Wired M12 Tee: <https://www.bannerengineering.com/th/en/products/part.64206.html>
* CSB-M1240M1240 64206- Parallel Wired M12 Splitter: <https://www.bannerengineering.com/th/en/products/part.807397.html>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# ctrlX CORE

Bosch rexroth

## All in one: The ultra-compact control system for automation

<figure><img src="/files/tJAxLzkI9LchrA7iAYGM" alt=""><figcaption><p>ctrlX AUTOMATION</p></figcaption></figure>

&#x20;“One control system for everything” means less engineering, fewer components and higher productivity. The modular software toolkit is based on the latest app technology and opens up new degrees of freedom when producing, providing and using functions.

[Learn more](https://apps.boschrexroth.com/microsites/ctrlx-automation/en/portfolio/ctrlx-core/)

### Video Lessons

1. [01- Using ctrlX CORE as PLC and Node-RED Server](/product-reviews/smart-devices/ctrlx-core/01-using-ctrlx-core-as-plc-and-node-red-server)
2. [02- Using ctrlX CORE as MQTT Broker](/product-reviews/smart-devices/ctrlx-core/02-using-ctrlx-core-as-mqtt-broker)
3. [03- Interfacing ctrlX CORE with ctrlX I/O via EtherCAT](/product-reviews/smart-devices/ctrlx-core/03-interfacing-ctrlx-core-with-ctrlx-i-o-via-ethercat)
4. [04- Introducing ctrlX CORE IDE App](/product-reviews/smart-devices/ctrlx-core/04-introducing-ctrlx-core-ide-app)
5. [05- Connecting OT with IT using Bosch DeviceBridge app](/product-reviews/smart-devices/ctrlx-core/05-connecting-ot-with-it-using-bosch-devicebridge-app)
6. [06- Interfacing ctrlX CORE with IO-Link master using EtherCAT](/product-reviews/smart-devices/ctrlx-core/06-interfacing-ctrlx-core-with-io-link-master-using-ethercat)
7. [07- ctrlX CORE as HMI- Part 1](/product-reviews/smart-devices/ctrlx-core/07-ctrlx-core-as-hmi-part-1)
8. [08- ctrlX CORE as HMI- Part 2](/product-reviews/smart-devices/ctrlx-core/08-ctrlx-core-as-hmi-part-2)

### Software and Hardware

&#x20;Check this page for relevant hardware and software information [Hardware and Software](/resources/hardware-and-software)


# 01- Using ctrlX CORE as PLC and Node-RED Server

Bosch rexroth

In this video, you will learn about ctrlX CORE and how this device can be used as a PLC and Node-RED server just by installing apps like a mobile phone

{% embed url="<https://www.youtube.com/watch?t=10s&v=nUtwLl7iTY4>" %}


# 02- Using ctrlX CORE as MQTT Broker

Bosch rexroth

In this video, you will learn about ctrlX CORE can be used as MQTT broker using an app from Cedalo

{% embed url="<https://www.youtube.com/watch?t=236s&v=5KTGMnNasZ4>" %}

**More information about the MQTT broker can be found here:** <https://developer.community.boschrexroth.com/t5/Store-and-How-to/Cedalo-Eclipse-Mosquitto-MQTT-Broker/ba-p/50927>&#x20;


# 03- Interfacing ctrlX CORE with ctrlX I/O via EtherCAT

Bosch rexroth

In this video, you will learn about ctrlX I/O can be accessed in PLC Engineering and Node-RED via EtherCAT

{% embed url="<https://youtu.be/Dvoej5hepOw?list=PLTLcz6IpeLYKemAlHvp13f3assh-VVyjF>" %}


# 04- Introducing ctrlX CORE IDE App

Bosch rexroth

## 🎥 Introducing ctrlX CORE IDE App

In this video, you will see how we can **run Python scripts in ctrlX CORE** and **trigger the scripts using Node-RED and PLC Engineering**

{% embed url="<https://youtu.be/skOmm1LhX3Y>" %}

## 📗 Resource files used in the video

### 📃 Python scripts

{% code title="Example1.py" lineNumbers="true" %}

```python
import functools import sys
#flush all prints
print = functools.partial(print, flush=True)
#For loop
for x in range(2):
    print(x)
sys.exit(0)
```

{% endcode %}

{% code title="Example2.py" lineNumbers="true" %}

```python
#Reading from ctrlX Data Layer
Channel1 = datalayer.read("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/input/data/XI110116/Channel_1.Value")

#Writing to ctrlX Data Layer
datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_1.Value", Channel1)

sys.exit(0)python
```

{% endcode %}

{% code title="Example3.py" lineNumbers="true" %}

```python
import time 
import sys

while True: 
    #Reading Channel 1 status from ctrlX Data Layer 
    Channel1 = datalayer.read("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/input/data/XI110116/Channel_1.Value")
    #Reading Channel 3 status from ctrlX Data Layer 
    Channel3 = datalayer.read("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/input/data/XI110116/Channel_3.Value")
    
    #blinking loop
    if Channel1 is True:
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_1.Value", True)
        time.sleep(1) #delay of 1s
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_2.Value", True)
        time.sleep(1) 
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_3.Value", True)
        time.sleep(1) 
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_3.Value", False)   
        time.sleep(1)      
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_2.Value", False)
        time.sleep(1)   
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_1.Value", False)
        time.sleep(1) 
    else:
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_1.Value", False)
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_2.Value", False)
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_3.Value", False)
    if Channel3 is True:
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_1.Value", False)
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_2.Value", False)
        datalayer.write("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/output/data/XI211116/Channel_3.Value", False)
        sys.exit(0)



```

{% endcode %}

{% code title="Example4PLC" overflow="wrap" lineNumbers="true" %}

```python
import sys
import time
import json

#Empty list
data = []

#Reading PLC variable from ctrlX Data Layer 
plcdata = datalayer.read("plc/app/Application/sym/PLC_PRG/ScriptOutData.Value")
data.append(plcdata)
time.sleep(0.3)

plcdata = datalayer.read("plc/app/Application/sym/PLC_PRG/ScriptOutData.Value") 
data.append(plcdata)
time.sleep(0.3)

plcdata = datalayer.read("plc/app/Application/sym/PLC_PRG/ScriptOutData.Value") 
data.append(plcdata)
time.sleep(0.3)

plcdata = datalayer.read("plc/app/Application/sym/PLC_PRG/ScriptOutData.Value") 
data.append(plcdata)
time.sleep(0.3)

plcdata = datalayer.read("plc/app/Application/sym/PLC_PRG/ScriptOutData.Value") 
data.append(plcdata)
time.sleep(0.3)

#Average function
def avg(num):
    sumOfNumbers = 0
    for t in num:
        sumOfNumbers = sumOfNumbers + t
    avg = sumOfNumbers / len(num)
    return avg

#Calculate Max
max_value = max(data)

#Calculate Min
min_value = min(data)

#Calculate Average
avg_value = avg(data)

#JSON to String
max_value_json = json.dumps({"type": "int16",  "value": max_value})
min_value_json = json.dumps({"type": "int16",  "value": min_value})
avg_value_json = json.dumps({"type": "float",  "value": avg_value})

#Writing to PLC variable in ctrlX Data Layer 
datalayer.write_json("plc/app/Application/sym/PLC_PRG/ScriptMax.Value",max_value_json )
datalayer.write_json("plc/app/Application/sym/PLC_PRG/ScriptMin.Value",min_value_json )
datalayer.write_json("plc/app/Application/sym/PLC_PRG/ScriptAvg.Value",avg_value_json )

sys.exit(0)
```

{% endcode %}

{% code title="Example5" overflow="wrap" lineNumbers="true" %}

```python
import sys

motion.attach_obj("X")
motion.attach_obj("Y")
motion.attach_obj("Z")
motion.attach_obj("Kinematics")

#Position1
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-100,-100,100],coord_sys="PCS",vel=2000,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-100,-100,0],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
while motion.get_axs_ipo_values("Z").get("pos") != 0:
    pass

motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-100,-100,100],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
#Position2
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[250,250,100],coord_sys="PCS",vel=2000,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[250,250,50],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
while motion.get_axs_ipo_values("Z").get("pos") != 50:
    pass   

motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[250,250,100],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
#Home position
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-400,-400,100],coord_sys="PCS",vel=2000,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
while motion.get_axs_ipo_values("X").get("pos") != -400:
    pass

motion.detach_obj("X")
motion.detach_obj("Y")
motion.detach_obj("Z")
motion.detach_obj("Kinematics")

sys.exit(0)
```

{% endcode %}

{% code title="Example6.py" overflow="wrap" lineNumbers="true" %}

```python
import time
import paho.mqtt.client as mqtt #import the client1
broker_address="192.168.0.112" 


#broker_address="iot.eclipse.org" #use external broker
client = mqtt.Client("ctrlX CORE") #create new instance
#client.username_pw_set("boschrexroth","boschrexroth")
client.connect(broker_address,port=1884) #connect to broker
#client.subscribe("ctrlxon")
client.publish("ctrlxon","Hello ctrlX World")#publish
print("closing")
sys.exit(0)
```

{% endcode %}

{% code title="Example7.py" overflow="wrap" lineNumbers="true" %}

```python
import sys
import time
import paho.mqtt.client as mqtt_client #import the client1


broker = '192.168.0.112'
port = 1884
topic = "ctrlxon"
client_id = 'ctrlX CORE'
#username = 'boschrexroth'
#password = 'boschrexroth'

motion.attach_obj("X")
motion.attach_obj("Y")
motion.attach_obj("Z")
motion.attach_obj("Kinematics")

def connect_mqtt():
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)
    # Set Connecting Client ID
    client = mqtt_client.Client(client_id)
    #client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client

#Connect to MQTT Broker
client = connect_mqtt()
client.loop_start()
client.publish(topic, "Program Starts")

#Position1
client.publish(topic, "Going to Position 1")
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-100,-100,100],coord_sys="PCS",vel=2000,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-100,-100,0],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
while motion.get_axs_ipo_values("Z").get("pos") != 0:
    time.sleep(1)
    pass
client.publish(topic,"Picked object")
client.publish(topic,"Going to Position 2")
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-100,-100,100],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
#Position2
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[250,250,100],coord_sys="PCS",vel=2000,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[250,250,50],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
while motion.get_axs_ipo_values("Z").get("pos") != 50:
    time.sleep(1)
    pass   
client.publish(topic,"Placed Object")
client.publish(topic,"Going to Home position")
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[250,250,100],coord_sys="PCS",vel=1500,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
#Home position
motion.kin_cmd_move_lin_abs(kin="Kinematics",pos=[-400,-400,100],coord_sys="PCS",vel=2000,acc=1000,dec=1000,jrk_acc=0,jrk_dec=0)
while motion.get_axs_ipo_values("X").get("pos") != -400:
    time.sleep(1)
    pass
client.publish(topic,"Program finished") # working
time.sleep(1)
motion.detach_obj("X")
motion.detach_obj("Y")
motion.detach_obj("Z")
motion.detach_obj("Kinematics")
sys.exit(0)
```

{% endcode %}

### 📃 PLC Engineering Program

{% code title="Variable declaration" lineNumbers="true" %}

```iecst
PROGRAM PLC_PRG
VAR
	fbIL_ScriptInstance: IL_ScriptInstance;
	StateInstance: CXA_PYTHON.INSTANCE_STATE;
	bEnableInstance: BOOL;
	bInOperationInstance: BOOL;
	bErrorInstance: BOOL;
	ErrorIDInstance: CXA_PYTHON.ERROR_CODE;
	ErrorIdentInstance: CXA_PYTHON.ERROR_STRUCT;
	strInstanceName: STRING := 'PLCInstance'; //Name of script instance to be created
	bResetInstance: BOOL;
	bAbortScript: BOOL;
	
	fbIL_StartScriptFile: IL_StartScriptFile;
	bExecuteFile: BOOL;
	bDoneFile: BOOL;
	bActiveFile: BOOL;
	bErrorFile: BOOL;
	ErrorIDFile: CXA_PYTHON.ERROR_CODE;
	ErrorIdentFile: CXA_PYTHON.ERROR_STRUCT;
	strFilePath: STRING(255) := 'activeConfiguration/script/Example2.py'; //Path to the file to be executed e.g. root folder of the active configuration
	//strFilePath: STRING(255) := 'activeConfiguration/script/Example4PLC.py'; //Path to the file to be executed e.g. root folder of the active configuration
	ParametersFile: ARRAY [0..9] OF STRING;
	ScriptOutData : INT;
	ScriptMax : INT;
	ScriptMin : INT;
	ScriptAvg : REAL;
END_VAR
```

{% endcode %}

{% code title="PLC Program" lineNumbers="true" %}

```iecst
fbIL_ScriptInstance(
	Enable:= bEnableInstance, 
	InOperation=> bInOperationInstance, 
	Error=> bErrorInstance, 
	ErrorID=> ErrorIDInstance, 
	ErrorIdent=> ErrorIdentInstance, 
	InstanceName:= strInstanceName, 
	ResetInstance:= bResetInstance, 
	AbortScript:= bAbortScript, 
	State=> StateInstance);
	
fbIL_StartScriptFile(
	Execute:= bExecuteFile, 
	Done=> bDoneFile, 
	Active=> bActiveFile, 
	Error=> bErrorFile, 
	ErrorID=> ErrorIDFile, 
	ErrorIdent=> ErrorIdentFile, 
	InstanceName:= strInstanceName, 
	FileName:= strFilePath, 
	Parameters:= ParametersFile);

PLC_PRG.ScriptOutData := PLC_PRG.ScriptOutData + 1;
IF PLC_PRG.ScriptOutData >= 200 THEN
	PLC_PRG.ScriptOutData := 0;
END_IF

IF PLC_PRG.ScriptOutData <= 100 THEN
	PLC_PRG.ScriptOutData := 100;
END_IF
```

{% endcode %}

### 📃 Node-RED Program

{% embed url="<https://github.com/thegeterrdone/ctrlX-CORE-IDE.git>" %}
Node-RED flows used in the video
{% endembed %}


# 05- Connecting OT with IT using Bosch DeviceBridge app

Bosch rexroth

In this video, you will learn how to bridge OT and IT using Bosch DeviceBridger app. The following are the topics covered in the video:

{% embed url="<https://www.youtube.com/watch?v=9SW-eqey5dc>" %}

### Video Timeline:

0:00 - Introduction\
0:20 Why to bridge IT and OT?\
1:05 - Bosch Device Bridge app\
3:18 - Example 1: Collect data from Delta PLC via MODBUS TCP/IP\
8:15 - Add business model to create an alert\
8:15 - Add business model to create an alert\
13:30 - Collect data from S7-1500 PLC via S7 Connection\
18:20 - Add business model in CSharp to write back data to Siemens PLC\
22:45 - Move data from Delta PLC to Siemens PLC using CSharp\
23:00 - Adding a conveter to scale the values\
30:00 - Collect 2 PLCs data and moce to the ctrlX CORE Data Layer\
33:27 - Read the data from the ctrlX Data Layer on the Node-RED\
35:35 - Adding a routing\
36:25 - Adding a Service Container and Publishing the project\
38:25 - Example 2: Collect the data from S7-1500 via OPC UA \
42:40 - Collect the data from Raspberry PI via MQTT\
46:50 - Adding data model\
44:45 - Send the data to Qubitro Cloud via MQTT\
51:07 - Send the data to Mondo Database (Cloud) via TCP/IP\
&#x20;59:59 - Outroduction


# 06- Interfacing ctrlX CORE with IO-Link master using EtherCAT

Bosch rexroth

This video will teach you how to interface ctrlX CORE with IO-Link master using EtherCAT. The following are the examples covered in the video:

{% embed url="<https://www.youtube.com/watch?v=2bgYXHP2zOQ>" %}

### Video Timeline:

[0:00](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=0s) - Introduction\
[0:50](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=50s) - What are we going to see?\
[1:25](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=85s) - Connections\
[2:11](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=131s) - Adding IO-Link master in the networks\
[6:28](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=388s) - Assign memories for IO-Link devices\
[11:27](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=687s) - Example 1: Actuating Signal Lamp using Distance sensor\
[19:45](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=1185s) - Example 2: Reading Vendor and Product ID of the IO-Link device using AoE\
[28:35](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=1715s) - Example 3: Reading the set-point of the sensor using AoE \
[31:52](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=1912s) - Example 4: Writing the set-point of the sensor using AoE \
[34:10](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=2050s) - Example 5: Visualizing IO-Link data on the Node-RED dashboard \
[37:49](https://www.youtube.com/watch?v=2bgYXHP2zOQ\&t=2269s) - Outroduction

### **Hardware and Software information**

* Software: ctrlX Works Software Version: 1.18.1
* Hardware: ctrlX CORE Plus

### **ESI description for IO-Link master AL1332**

{% embed url="<https://www.ifm.com/de/de/product/AL1332?tab=documents>" %}

### **Exam**ple 1: How to actuate IO-Link actuator using IO-Link sensor connected to ctrlX CORE via IO-Link master device AL1332.&#x20;

{% code title="GVL declaration" overflow="wrap" lineNumbers="true" %}

```iecst
{attribute 'qualified_only'}
VAR_GLOBAL
	//Distance Sensor
	rawbyte0 AT %IB0 : BYTE;
	rawbyte1 AT %IB1 : BYTE;

	//SignalLamp
	//Segment1
	segment1 AT %QB5 : BYTE;
	segment2 AT %QB4 : BYTE;
	segment3 AT %QB3 : BYTE;
	segment4 AT %QB2 : BYTE;
	segment5 AT %QB1 : BYTE;
END_VAR
```

{% endcode %}

{% code title="PLC variable declaration" overflow="wrap" lineNumbers="true" %}

```iecst
PROGRAM PLC_PRG
VAR
	wData : WORD;
	iDistance : INT;
	bOutput : BOOL;
	bySegment1 : BYTE;
END_VAR
```

{% endcode %}

{% code title="PLC code" overflow="wrap" lineNumbers="true" %}

```iecst
// -------------------- Reading Distance sensor process output --------------------

//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);

//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));

//Defining limits
IF iDistance > 200 THEN
	iDistance := 200;
END_IF

IF iDistance < 5 THEN
	iDistance := 5;
END_IF

//Set point output
bOutput := GVL.rawbyte1.0;

//SignalLamp condition
IF bOutput = TRUE THEN
  // 2= Green
	GVL.segment1 := 2;
	GVL.segment2 := 2;
	GVL.segment3 := 2;
	GVL.segment4 := 2;
	GVL.segment5 := 2;
	ELSE //4= RED
	GVL.segment1 := 4;
	GVL.segment2 := 4;
	GVL.segment3 := 4;
	GVL.segment4 := 4;
	GVL.segment5 := 4;
END_IF
```

{% endcode %}

### **Exam**ple 2: How to read Vendor and Product ID of IO-Link device in PLC Engineering app using AoE protocol?

{% code title="GVL declaration" overflow="wrap" lineNumbers="true" %}

```iecst
{attribute 'qualified_only'}
VAR_GLOBAL
	//Distance Sensor
	rawbyte0 AT %IB0 : BYTE;
	rawbyte1 AT %IB1 : BYTE;

	//SignalLamp
	//Segment1
	segment1 AT %QB5 : BYTE;
	segment2 AT %QB4 : BYTE;
	segment3 AT %QB3 : BYTE;
	segment4 AT %QB2 : BYTE;
	segment5 AT %QB1 : BYTE;
END_VARde
```

{% endcode %}

{% code title="PLC variable declaration" overflow="wrap" lineNumbers="true" %}

```iecst
PROGRAM PLC_PRG
VAR
	wData : WORD;
	iDistance : INT;
	bOutput : BOOL;
	bySegment1 : BYTE;
	
// ---------------- Read AoE -----------------------------	

//Name of instance
	strMasterName : STRING := 'ethercatmaster';

//Ethercat address of ifm AL1332
	uiEthercatAddr : UINT := 1005;
	strTargetNetId   : IL_ECAT_AOE_NET_ID := (Byte0:= 172, Byte1:=31, Byte2:= 254, Byte3:= 254, Byte4:= 0, Byte5:= 1);

//Vendor variable declaration for IO Link read
	strVendor : STRING(32) := '';  //Variable in which the read result (vendor) value will be copied
	fbIOLinkRead_Vendor: IL_ECATAoeRead;
		
	uiIoLinkPortNbr_Vendor  : UINT := 1;//X1 = Plug, the IO-Link device is connected
	wIoLinkIndex_Vendor     : WORD := 16;   //IO-Link index = 16 (vendor)
	byIoLinkSubIndex_Vendor : BYTE := 0; 	//IO-Link Subindex = 0 (vendor)
	
	bVendor_Error: BOOL;
	bVendor_Done: BOOL;
	bRead_Vendor: BOOL;

	
// X01 Product ID variable declaration for IO Link Read
	strProductID : STRING(32) := '';  //Variable in which the read result (Product ID) value will be copied
	fbIOLinkRead_ProductID: IL_ECATAoeRead;
		
	uiIoLinkPortNbr_ProductID  : UINT := 1;	//X1 = Plug, the IO-Link device is connected
	wIoLinkIndex_ProductID     : WORD := 19;//IO-Link index = 19 (product ID)
	byIoLinkSubIndex_ProductID : BYTE :=0;//IO-Link Subindex = 0 (product ID)
	
	bProductID_Error: BOOL;
	bProductID_Done: BOOL;
	bRead_ProductID: BOOL;
	
END_VAR
```

{% endcode %}

{% code title="PLC code" overflow="wrap" lineNumbers="true" %}

```iecst
//Read Aoe vendor ID
	//Read function
	fbIOLinkRead_Vendor(
	Execute:= bRead_Vendor,  //Execute bit 						
	MasterName:= ADR(strMasterName), //Instance name
	SlaveAddress:= uiEthercatAddr,  //EtherCAT address of IO-Link master
	TargetNetId:= strTargetNetId ,  //Refer from ctrlX I/O
	TargetPort:= 16#1000 + uiIoLinkPortNbr_Vendor, //ADS communication port = 16#1000 + IO-Link port number 
	IndexGroup:= 16#F302, //Fixed for IFM IO-Link
	//IDXOFFS Index Offset 
	//Bits 0-7: IO-Link subindex
	//Bits 8-15: 00000000
	//Bits 16-31: IO-Link index
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_Vendor),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_Vendor)), 
	SizeOfValue:= SIZEOF(strVendor), //Byte requirement
	ValueAdr:= ADR(strVendor)); //Value
	
IF TRUE = fbIOLinkRead_Vendor.Done THEN
	bVendor_Error := FALSE;  // Reset error
	bVendor_Done := TRUE;    
END_IF;

IF TRUE = fbIOLinkRead_Vendor.Error THEN
	bVendor_Error := TRUE;   // Error handling
	bVendor_Done := FALSE;
END_IF;
	
//Read Aoe Product ID
	fbIOLinkRead_ProductID(
	Execute:= bRead_ProductID, 
	MasterName:= ADR(strMasterName), 
	SlaveAddress:= uiEthercatAddr, 
	TargetNetId:= strTargetNetId , 
	TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID, 
	IndexGroup:= 16#F302, 
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID)), 
	SizeOfValue:= SIZEOF(strProductID), 
	ValueAdr:= ADR(strProductID), 
);

// -------------------- Reading Distance sensor process output --------------------

//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);

//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));

//Defining limits
IF iDistance > 200 THEN
	iDistance := 200;
END_IF

IF iDistance < 5 THEN
	iDistance := 5;
END_IF

//Set point output
bOutput := GVL.rawbyte1.0;

//SignalLamp condition
IF bOutput = TRUE THEN
	GVL.segment1 := 2;
	GVL.segment2 := 2;
	GVL.segment3 := 2;
	GVL.segment4 := 2;
	GVL.segment5 := 2;
	ELSE
	GVL.segment1 := 4;
	GVL.segment2 := 4;
	GVL.segment3 := 4;
	GVL.segment4 := 4;
	GVL.segment5 := 4;
END_IF
```

{% endcode %}

### **Exam**ple 3: How to read the Set-Point of distance sensor in crtlX CORE?

{% code title="GVL declaration" overflow="wrap" lineNumbers="true" %}

```iecst
{attribute 'qualified_only'}
VAR_GLOBAL
	//Distance Sensor
	rawbyte0 AT %IB0 : BYTE;
	rawbyte1 AT %IB1 : BYTE;

	//SignalLamp
	//Segment1
	segment1 AT %QB5 : BYTE;
	segment2 AT %QB4 : BYTE;
	segment3 AT %QB3 : BYTE;
	segment4 AT %QB2 : BYTE;
	segment5 AT %QB1 : BYTE;
END_VAR
```

{% endcode %}

{% code title="PLC variable declaration" overflow="wrap" lineNumbers="true" %}

```iecst
PROGRAM PLC_PRG
VAR
	wData : WORD;
	iDistance : INT;
	bOutput : BOOL;
	bySegment1 : BYTE;
	
// ---------------- Read AoE -----------------------------	

//Name of instance
	strMasterName : STRING := 'ethercatmaster';

//Ethercat address of ifm AL1332
	uiEthercatAddr : UINT := 1005;
	strTargetNetId   : IL_ECAT_AOE_NET_ID := (Byte0:= 172, Byte1:=31, Byte2:= 254, Byte3:= 254, Byte4:= 0, Byte5:= 1);

//Vendor variable declaration for IO Link read
	strVendor : STRING(32) := '';  				//Variable in which the read result (vendor) value will be copied
	fbIOLinkRead_Vendor: IL_ECATAoeRead;
		
	uiIoLinkPortNbr_Vendor  : UINT := 1;			//X1 = Plug, the IO-Link device is connected
	wIoLinkIndex_Vendor     : WORD := 16;    		//IO-Link index = 16 (vendor)
	byIoLinkSubIndex_Vendor : BYTE := 0; 		//IO-Link Subindex = 0 (vendor)
	
	bVendor_Error: BOOL;
	bVendor_Done: BOOL;
	bRead_Vendor: BOOL;

	
// X01 Product ID variable declaration for IO Link Read
	strProductID : STRING(32) := '';  			//Variable in which the read result (Product ID) value will be copied
	fbIOLinkRead_ProductID: IL_ECATAoeRead;
		
	uiIoLinkPortNbr_ProductID  : UINT := 1;		//X1 = Plug, the IO-Link device is connected
	wIoLinkIndex_ProductID     : WORD := 19;    	//IO-Link index = 19 (product ID)
	byIoLinkSubIndex_ProductID : BYTE :=0; 		//IO-Link Subindex = 0 (product ID)
	
	bProductID_Error: BOOL;
	bProductID_Done: BOOL;
	bRead_ProductID: BOOL;

// X01 Set point of Variable declaration for IO Link Read  
	uiSetPointRead: UINT;
	uiSetPointRead_swap: UINT; //Varible for byte swap output
	bRead_SetPoint: BOOL;
	
	fbIOLinkRead_ProductID_SetPoint: IL_ECATAoeRead;

	uiIoLinkPortNbr_ProductID_SetPoint  : UINT := 1;		//X1 = Plug, the IO-Link device is connected
	wIoLinkIndex_ProductID_SetPoint     : WORD := 60;    	//IO-Link index = 60 (Set Point)
	byIoLinkSubIndex_ProductID_SetPoint : BYTE := 1; 		//IO-Link Subindex = 1 (Set Point)
	
	bProductID_SetPoint_Error: BOOL;
	bProductID_SetPoint_Done: BOOL;
	
END_VAR
```

{% endcode %}

{% code title="PLC code" overflow="wrap" lineNumbers="true" %}

```iecst
//Read Aoe vendor ID
	
	//Read function
	fbIOLinkRead_Vendor(
	Execute:= bRead_Vendor,  //Execute bit 						
	MasterName:= ADR(strMasterName), //Instance name
	SlaveAddress:= uiEthercatAddr,  //EtherCAT address of IO-Link master
	TargetNetId:= strTargetNetId ,  //Refer from ctrlX I/O
	TargetPort:= 16#1000 + uiIoLinkPortNbr_Vendor, //ADS communication port = 16#1000 + IO-Link port number 
	IndexGroup:= 16#F302, //Fixed for IFM IO-Link
	//IDXOFFS Index Offset 
	//Bits 0-7: IO-Link subindex
	//Bits 8-15: 00000000
	//Bits 16-31: IO-Link index
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_Vendor),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_Vendor)), 
	SizeOfValue:= SIZEOF(strVendor), //Byte requirement
	ValueAdr:= ADR(strVendor)); //Value
	
IF TRUE = fbIOLinkRead_Vendor.Done THEN
	bVendor_Error := FALSE;  // Reset error
	bVendor_Done := TRUE;    
END_IF;

IF TRUE = fbIOLinkRead_Vendor.Error THEN
	bVendor_Error := TRUE;   // Error handling
	bVendor_Done := FALSE;
END_IF;
	
//Read Aoe Product ID
	fbIOLinkRead_ProductID(
	Execute:= bRead_ProductID, 
	MasterName:= ADR(strMasterName), 
	SlaveAddress:= uiEthercatAddr, 
	TargetNetId:= strTargetNetId , 
	TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID, 
	IndexGroup:= 16#F302, 
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID)), 
	SizeOfValue:= SIZEOF(strProductID), 
	ValueAdr:= ADR(strProductID), 
);

//Read Aoe Product ID Set Point
fbIOLinkRead_ProductID_SetPoint(
	Execute:= bRead_SetPoint, 
	MasterName:= ADR(strMasterName), 
	SlaveAddress:= uiEthercatAddr, 
	TargetNetId:= strTargetNetId , 
	TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID_SetPoint, 
	IndexGroup:= 16#F302, 
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID_SetPoint),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID_SetPoint)), 
	SizeOfValue:= SIZEOF(uiSetPointRead), 
	ValueAdr:= ADR(uiSetPointRead), 
);

//Byte swap of Set Point read
uiSetPointRead_swap := WORD_TO_UINT(IL_SwapWord(uiSetPointRead));

IF TRUE = fbIOLinkRead_ProductID_SetPoint.Done THEN
	bProductID_SetPoint_Error := FALSE;  // Reset error
	bProductID_SetPoint_Done := TRUE;
END_IF;

IF TRUE = fbIOLinkRead_ProductID_SetPoint.Error THEN
	bProductID_SetPoint_Error := TRUE;  // Error handling
	bProductID_SetPoint_Done := FALSE;
END_IF;

// -------------------- Reading Distance sensor process output --------------------

//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);

//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));

//Defining limits
IF iDistance > 200 THEN
	iDistance := 200;
END_IF

IF iDistance < 5 THEN
	iDistance := 5;
END_IF

//Set point output
bOutput := GVL.rawbyte1.0;

//SignalLamp condition
IF bOutput = TRUE THEN
	GVL.segment1 := 2;
	GVL.segment2 := 2;
	GVL.segment3 := 2;
	GVL.segment4 := 2;
	GVL.segment5 := 2;
	ELSE
	GVL.segment1 := 4;
	GVL.segment2 := 4;
	GVL.segment3 := 4;
	GVL.segment4 := 4;
	GVL.segment5 := 4;
END_IF
```

{% endcode %}

### **Exam**ple 4: How to write the Set-Point of distance sensor in crtlX CORE?

{% code title="GVL declaration" overflow="wrap" lineNumbers="true" %}

```iecst
{attribute 'qualified_only'}
VAR_GLOBAL
	//Distance Sensor
	rawbyte0 AT %IB0 : BYTE;
	rawbyte1 AT %IB1 : BYTE;

	//SignalLamp
	//Segment1
	segment1 AT %QB5 : BYTE;
	segment2 AT %QB4 : BYTE;
	segment3 AT %QB3 : BYTE;
	segment4 AT %QB2 : BYTE;
	segment5 AT %QB1 : BYTE;
END_VAR
```

{% endcode %}

{% code title="PLC variables declaration" overflow="wrap" lineNumbers="true" %}

```iecst
PROGRAM PLC_PRG 
VAR 

wData : WORD; 
iDistance : INT; 
bOutput : BOOL; 
bySegment1 : BYTE;

// ---------------- Read AoE -----------------------------
//Name of instance
strMasterName : STRING := 'ethercatmaster';
//Ethercat address of ifm AL1332 
uiEthercatAddr : UINT := 1005; strTargetNetId : IL_ECAT_AOE_NET_ID := (Byte0:= 172, Byte1:=31, Byte2:= 254, Byte3:= 254, Byte4:= 0, Byte5:= 1);

//Vendor variable declaration for IO Link read 
strVendor : STRING(32) := ''; //Variable in which the read result (vendor) value will be copied 
fbIOLinkRead_Vendor: IL_ECATAoeRead;
uiIoLinkPortNbr_Vendor  : UINT := 1;//X1 = Plug, the IO-Link device is connected
wIoLinkIndex_Vendor     : WORD := 16; 	//IO-Link index = 16 (vendor)
byIoLinkSubIndex_Vendor : BYTE := 0; 	//IO-Link Subindex = 0 (vendor)
bVendor_Error: BOOL;
bVendor_Done: BOOL;
bRead_Vendor: BOOL;

// X01 Product ID variable declaration for IO Link Read 
strProductID : STRING(32) := ''; //Variable in which the read result (Product ID) value will be copied 
fbIOLinkRead_ProductID: IL_ECATAoeRead;
uiIoLinkPortNbr_ProductID  : UINT := 1;	//X1 = Plug, the IO-Link device is connected
wIoLinkIndex_ProductID     : WORD := 19; //IO-Link index = 19 (product ID)
byIoLinkSubIndex_ProductID : BYTE :=0; 	//IO-Link Subindex = 0 (product ID)
bProductID_Error: BOOL;
bProductID_Done: BOOL;
bRead_ProductID: BOOL;

// X01 Set point of Variable declaration for IO Link Read 
uiSetPointRead: UINT;
uiSetPointRead_swap: UINT; //Varible for byte swap output
bRead_SetPoint: BOOL;
fbIOLinkRead_ProductID_SetPoint: IL_ECATAoeRead;
uiIoLinkPortNbr_ProductID_SetPoint  : UINT := 1;//X1 = Plug, the IO-Link device is connected
wIoLinkIndex_ProductID_SetPoint     : WORD := 60;//IO-Link index = 60 (Set Point)
byIoLinkSubIndex_ProductID_SetPoint : BYTE := 1; //IO-Link Subindex = 1 (Set Point)
bProductID_SetPoint_Error: BOOL;
bProductID_SetPoint_Done: BOOL;

//------------------Write AoE------------------------- 
uiSetPointWrite : UINT := 25;
uiSetPointWrite_swap: UINT;
bWrite_SetPoint: BOOL;
fbIOLinkWrite_ProductID_SetPoint_write: IL_ECATAoeWrite;
bProductID_SetPoint_Write_Error: BOOL;
bProductID_SetPoint_Write_Done: BOOL;

END_VAR
```

{% endcode %}

{% code title="PLC code" overflow="wrap" lineNumbers="true" %}

```iecst
//Read Aoe vendor ID
	
	//Read function
	fbIOLinkRead_Vendor(
	Execute:= bRead_Vendor,  //Execute bit 						
	MasterName:= ADR(strMasterName), //Instance name
	SlaveAddress:= uiEthercatAddr,  //EtherCAT address of IO-Link master
	TargetNetId:= strTargetNetId ,  //Refer from ctrlX I/O
	TargetPort:= 16#1000 + uiIoLinkPortNbr_Vendor, //ADS communication port = 16#1000 + IO-Link port number 
	IndexGroup:= 16#F302, //Fixed for IFM IO-Link
	//IDXOFFS Index Offset 
	//Bits 0-7: IO-Link subindex
	//Bits 8-15: 00000000
	//Bits 16-31: IO-Link index
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_Vendor),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_Vendor)), 
	SizeOfValue:= SIZEOF(strVendor), //Byte requirement
	ValueAdr:= ADR(strVendor)); //Value
	
IF TRUE = fbIOLinkRead_Vendor.Done THEN
	bVendor_Error := FALSE;  // Reset error
	bVendor_Done := TRUE;    
END_IF;

IF TRUE = fbIOLinkRead_Vendor.Error THEN
	bVendor_Error := TRUE;   // Error handling
	bVendor_Done := FALSE;
END_IF;
	
//Read Aoe Product ID
	fbIOLinkRead_ProductID(
	Execute:= bRead_ProductID, 
	MasterName:= ADR(strMasterName), 
	SlaveAddress:= uiEthercatAddr, 
	TargetNetId:= strTargetNetId , 
	TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID, 
	IndexGroup:= 16#F302, 
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID)), 
	SizeOfValue:= SIZEOF(strProductID), 
	ValueAdr:= ADR(strProductID), 
);

//Read Aoe Product ID Set Point
fbIOLinkRead_ProductID_SetPoint(
	Execute:= bRead_SetPoint, 
	MasterName:= ADR(strMasterName), 
	SlaveAddress:= uiEthercatAddr, 
	TargetNetId:= strTargetNetId , 
	TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID_SetPoint, 
	IndexGroup:= 16#F302, 
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID_SetPoint),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID_SetPoint)), 
	SizeOfValue:= SIZEOF(uiSetPointRead), 
	ValueAdr:= ADR(uiSetPointRead), 
);

//Byte swap of Set Point read
uiSetPointRead_swap := WORD_TO_UINT(IL_SwapWord(uiSetPointRead));

IF TRUE = fbIOLinkRead_ProductID_SetPoint.Done THEN
	bProductID_SetPoint_Error := FALSE;  // Reset error
	bProductID_SetPoint_Done := TRUE;
END_IF;

IF TRUE = fbIOLinkRead_ProductID_SetPoint.Error THEN
	bProductID_SetPoint_Error := TRUE;  // Error handling
	bProductID_SetPoint_Done := FALSE;
END_IF;


//Write Aoe Product ID Set Point
	//uiSetPointWrite_conv := ROR(SetPointWrite,8);
	uiSetPointWrite_swap := WORD_TO_UINT(IL_SwapWord(uiSetPointWrite));
	fbIOLinkWrite_ProductID_SetPoint_write(
	Execute:= bWrite_SetPoint, 
	MasterName:= ADR(strMasterName), 
	SlaveAddress:= uiEthercatAddr, 
	TargetNetId:= strTargetNetId, 
	TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID_SetPoint, 
	IndexGroup:= 16#F302, 
	IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID_SetPoint),16))
					OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID_SetPoint)), 
	ValueAdr:= ADR(uiSetPointWrite_swap), 	
	SizeOfValue:= SIZEOF(uiSetPointWrite_swap), 
	//SizeOfValue:= 2,
);

IF TRUE = fbIOLinkWrite_ProductID_SetPoint_write.Done THEN
	bProductID_SetPoint_Write_Error := FALSE;// FB Finished -> Product name was read,
	bProductID_SetPoint_Write_Done := TRUE;
END_IF;

IF TRUE = fbIOLinkWrite_ProductID_SetPoint_write.Error THEN
	bProductID_SetPoint_Write_Error := TRUE;// Error handling
	bProductID_SetPoint_Write_Done := FALSE;
END_IF;


// -------------------- Reading Distance sensor process output --------------------

//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);

//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));

//Defining limits
IF iDistance > 200 THEN
	iDistance := 200;
END_IF

IF iDistance < 5 THEN
	iDistance := 5;
END_IF

//Set point output
bOutput := GVL.rawbyte1.0;

//SignalLamp condition
IF bOutput = TRUE THEN
	GVL.segment1 := 2;
	GVL.segment2 := 2;
	GVL.segment3 := 2;
	GVL.segment4 := 2;
	GVL.segment5 := 2;
	ELSE
	GVL.segment1 := 4;
	GVL.segment2 := 4;
	GVL.segment3 := 4;
	GVL.segment4 := 4;
	GVL.segment5 := 4;
END_IF
```

{% endcode %}

### Example 5: Visualize the parameters on the Node-RED dashboard

<figure><img src="/files/32hf5E6pDI10XdZWReUS" alt="Node-RED Dashboard"><figcaption><p>Node-RED Dashboard</p></figcaption></figure>

{% file src="/files/ARdzIomXXsn8crYgPlPk" %}
Node-RED flow
{% endfile %}


# 07- ctrlX CORE as HMI- Part 1

WebIQ

🎥 In this video, you will see how to create an HMI using WebIQ designer and run it in the ctrlX CORE on the WebIQ runtime app.&#x20;

The following topics are covered in the video:

* 👉 Create responsive HMI layout
* &#x20;👉 Creating OPC UA server in WebIQ
* &#x20;👉 Simulating the values on the HMI
* &#x20;👉 Adding a trend graph 📈

{% embed url="<https://youtu.be/tSoHGuLMdOE>" %}

### Timeline:

[0:00](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=0s) - Introduction\
[0:30](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=30s) - What is WebIQ\
[2:33](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=153s) - Example 1- Create your first HMI Project\
[4:45](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=285s) - Adding Header, Footer and Content\
[11:40](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=700s) - Adding multi screen panel\
[20:30](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1230s) - Adding WebIQ internal OPC UA Server\
[21:30](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1290s) - Adding OPC UA tags\
[25:03](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1503s) - Adding Widgets on the screen\
[26:25](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1585s) - Connecting the widgets with the OPC UA Tags\
[30:35](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1835s) - Running the HMI project on the ctrlX CORE\
[34:20](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=2060s): Outroduction

### Reference links:&#x20;

👉[About ctrlX AUTOMATION](https://apps.boschrexroth.com/microsites/ctrlx-automation/en/?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)\
👉[More about Smart HMI](https://apps.boschrexroth.com/microsites/ctrlx-automation/en/ctrlx-world/partner/smart-hmi-en/?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)\
👉[More about Smart HMI WebIQ Server](https://developer.community.boschrexroth.com/t5/store-and-how-to/smart-hmi-webiq-server/ba-p/18412?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)\
👉[Get WebIQ Designer](https://developer.community.boschrexroth.com/t5/store-and-how-to/smart-hmi-webiq-server/ba-p/18412?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)

### **Hardware and Software information**

* Software: [WebIQ Designer (free 30 days trial)](https://developer.community.boschrexroth.com/t5/store-and-how-to/smart-hmi-webiq-server/ba-p/18412?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)
* Hardware: ctrlX CORE Plus


# 08- ctrlX CORE as HMI- Part 2

WebIQ

🎥 In this video, you will see how to create an HMI for S7-1500 PLC using WebIQ. The communication between HMI and PLC is via OPC UA to read and write the information.

👀 In the video, you will see how to create:

* 📊 Gauges
* 🎚️ Buttons
* 📈 Trends
* 🔔 Alarms and Notifications

{% embed url="<https://youtu.be/6Lg5qWHiCxI>" %}

### Timeline:

[0:00](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=0s) - Introduction\
[0:30](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=30s) - What is WebIQ\
[2:33](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=153s) - Example 1- Create your first HMI Project\
[4:45](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=285s) - Adding Header, Footer and Content\
[11:40](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=700s) - Adding multi screen panel\
[20:30](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1230s) - Adding WebIQ internal OPC UA Server\
[21:30](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1290s) - Adding OPC UA tags\
[25:03](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1503s) - Adding Widgets on the screen\
[26:25](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1585s) - Connecting the widgets with the OPC UA Tags\
[30:35](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=1835s) - Running the HMI project on the ctrlX CORE\
[34:20](https://www.youtube.com/watch?v=tSoHGuLMdOE\&t=2060s): Outroduction

### Reference links:&#x20;

👉[About ctrlX AUTOMATION](https://apps.boschrexroth.com/microsites/ctrlx-automation/en/?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)\
👉[More about Smart HMI](https://apps.boschrexroth.com/microsites/ctrlx-automation/en/ctrlx-world/partner/smart-hmi-en/?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)\
👉[More about Smart HMI WebIQ Server](https://developer.community.boschrexroth.com/t5/store-and-how-to/smart-hmi-webiq-server/ba-p/18412?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)\
👉[Get WebIQ Designer](https://developer.community.boschrexroth.com/t5/store-and-how-to/smart-hmi-webiq-server/ba-p/18412?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)

### **Hardware and Software information**

* Software: [WebIQ Designer (free 30 days trial)](https://developer.community.boschrexroth.com/t5/store-and-how-to/smart-hmi-webiq-server/ba-p/18412?utm_medium=social\&utm_source=youtube.com\&utm_campaign=en_ae_ctrlx_wk1123\&utm_content=developer-engineer-director\&utm_term=1503-ytrs)
* Hardware: ctrlX CORE Plus


# Virtual ctrlX WORKS

Don't have a hardware? Do not worry, you can still play around with ctrlX Virtual Core. The steps are mentioned in the following link:

1. **How to setup virtual ctrlX CORE in your PC**\
   <https://developer.community.boschrexroth.com/t5/Store-and-How-to/Setting-up-a-ctrlX-COREvirtual/ba-p/11985>&#x20;


# Smart Platforms


# Virtual PLCs

In this page, you will find my work with various Virtual PLCs providers.

Virtual PLCs (vPLCs) are software-based controllers that run your automation logic on general-purpose hardware. Linux IPCs, edge devices like Revolution Pi, even containers — instead of a dedicated PLC CPU. The result: no controller hardware to buy, faster deployment, central fleet management, and modern IT-style workflows (CI/CD, remote monitoring) applied to PLC programming.

I have tested the following vPLC platforms hands-on. Here is a brief summary of my work with each, so you can jump straight to the one that matches your use case.

### ⚡ Autonomy Edge: OpenPLC redefined

Autonomy takes the open-source **OpenPLC** runtime and adds **cloud orchestration**, letting you build, test, and deploy automation logic without ever buying a PLC CPU. My work with this platform covers:

* A complete **OpenPLC walkthrough** — setting up cloud orchestration and deploying your first virtual PLC
* **Interfacing with an IO-Link master** over MODBUS TCP/IP for real-time vibration monitoring and signaling on real hardware
* Using **Python Function Blocks** in the OpenPLC Editor and streaming live PLC data to a ThingsBoard cloud dashboard

Learn more: [Autonomy Edge- OpenPLC redefined](/product-reviews/smart-platforms/virtual-plcs/autonomy-edge-openplc-redefined)

### 🖥️ OTee — Open Architecture Real-time Virtual PLCs

**OTee.io** is a free platform for creating and deploying virtual PLCs on Linux-based edge devices. I deployed a fully functional vPLC on a **Revolution Pi** in a step-by-step live demo, covering:

* **IEC 61131-3 Structured Text** programming with tags, variables, and alarms in OTee's cloud editor
* **Modbus TCP communication** to field I/O, with remote tag browsing and live troubleshooting
* Platform features like **role-based access control, fleet management, and CI/CD pipelines** from a centralized secure cloud

Learn more: [OTee- Open Architecture Real time Virtual PLCs](/product-reviews/smart-platforms/virtual-plcs/otee-open-architecture-real-time-virtual-plcs)

{% content-ref url="<https://wiki.codeandcompile.com/product-reviews/smart-platforms/virtual-plcs/otee-open-architecture-real-time-virtual-plcs>" %}
<https://wiki.codeandcompile.com/product-reviews/smart-platforms/virtual-plcs/otee-open-architecture-real-time-virtual-plcs>
{% endcontent-ref %}


# Autonomy Edge- OpenPLC redefined

Run a Real PLC Without Buying Hardware. You no longer need a physical PLC CPU to start building, testing, and deploying automation logic.

In the articles below, you will learn how to set up Cloud Orchestration for Virtual PLCs using an open-source platform from Autonomy and how to interface it with real hardware.

<figure><img src="/files/rZpplSNx9PJq7baLzjF8" alt=""><figcaption></figcaption></figure>

* [OpenPLC Walkthrough](/product-reviews/smart-platforms/virtual-plcs/autonomy-edge-openplc-redefined/openplc-walkthrough)
* [OpenPLC interfacing with IO-Link Master](/product-reviews/smart-platforms/virtual-plcs/autonomy-edge-openplc-redefined/openplc-interfacing-with-io-link-master)
* [OpenPLC with Python FB](/product-reviews/smart-platforms/virtual-plcs/autonomy-edge-openplc-redefined/openplc-with-python-fb)

{% hint style="info" %}
Each article is intentionally architecture-focused and vendor-neutral, reflecting how ThingsBoard is deployed in real industrial environments.
{% endhint %}


# OpenPLC Walkthrough

Industrial automation is evolving. You no longer need a physical PLC CPU to start building, testing, and deploying automation logic.

In this article, I’ll show you:

* What is OpenPLC really?
* Why virtual PLCs matter?
* How can you deploy it?
* Where does it fit in modern edge architectures?
* And how can you test it with a digital twin?

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FWAyhK3VG0KIv0e4AXrcK%2FOpenPLC.mp4?alt=media&token=9d7d4df1-f29a-44d4-8301-fe4580cb1e99>" %}

## Watch the Full Video First

Before reading further, I recommend watching the complete walkthrough:

{% embed url="<https://www.youtube.com/watch?v=6-YQE0Mq_T0>" %}

In this video, I demonstrate:

* Installing and running OpenPLC
* Programming a simple logic
* Deploying it on an edge environment
* Connecting it to a simulation

***

## What is OpenPLC?

**OpenPLC** is an open-source IEC 61131-3 PLC runtime.

<figure><img src="/files/zRbyVG9NO6fmCd4UTNrk" alt=""><figcaption></figcaption></figure>

It allows you to:

* Program in Ladder, Structured Text (ST), and FBD
* Run on Linux, Raspberry Pi, or industrial PCs
* Deploy inside Docker containers
* Communicate via Modbus, OPC UA, MQTT
* Integrate with edge and cloud systems

> In simple words: OpenPLC = A real PLC runtime running on standard hardware.

***

## Why Virtual PLCs Matter

Traditional PLC setup:

* PLC CPU, IO modules, Wiring, Power supply
* Hardware cost

Virtual PLC setup:

* Edge device with OpenPLC runtime
* Software-based IO
* Cloud Orchestration

This enables:

* Remote development and Safe testing
* Scalable training labs with Faster prototyping
* Lower cost entry into automation

> For educators and engineers, this is powerful.

***

## Where Can You Run OpenPLC?

OpenPLC is extremely flexible.

You can deploy it on:

* Raspberry Pi, Industrial PCs
* Docker containers
* Edge gateways
* Linux-based embedded systems

> This makes it ideal for IIoT prototyping, Remote labs, and educational institutions and Edge-to-cloud architectures

***

## How to Get Started with OpenPLC

Sign up for free at their Official Website: 🔗 <https://autonomylogic.com/>. Watch the video for step by step instruction

***

## Testing Your PLC Logic Without Real Hardware

Now comes the important question: How do you test PLC logic if you don’t have physical IO? You use a digital twin. And this is where **Simumatik** becomes extremely powerful.

<figure><img src="/files/dNXjkBAr7l5AKORRUO9T" alt=""><figcaption></figcaption></figure>

## Simulate Machines with Simumatik

**Simumatik** is a browser-based industrial simulation platform. It allows you to:

* Build machine simulations
* Connect directly to OpenPLC
* Simulate sensors and actuators
* Teach automation safely
* Validate control logic in 3D environments

In this setup:

OpenPLC → Control Brain\
Simumatik → Virtual Machine

> Together you get a complete virtual automation lab.

***

## 🎯 Interested in Trying Simumatik?

We are officially offering **Simumatik educational licenses**.

If you:

* Want to use it in your school
* Build a training lab
* Practice PLC programming in simulation
* Teach automation remotely

Learn more about that here: <https://codeandcompile.com/simumatik>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# OpenPLC interfacing with IO-Link Master

In this article, you will learn about vPLC integration with IO-Link master via MODBUS TCP/IP for real time vibration monitoring and signaling

## Real-Time Vibration Monitoring with Smart Signaling via Modbus TCP/IP

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FHVHGB1UM5ra5lxFFou1P%2FOpenPLC.mp4?alt=media&token=2699e9aa-168a-4f6c-b84a-b42de8b725ea>" %}

***

### What This Project Does

In this project, we use a **reComputer running OpenPLC runtime (vPLC)** to:

* Read **real-time vibration data** (X, Y, Z axes + temperature) from a Balluff condition monitoring sensor
* Detect objects using a **laser photo-electric sensor**
* Drive a **Balluff Smart Light** as a visual signal output
* All sensor communication happens through a **Balluff IO-Link Master** over **Modbus TCP/IP**

***

{% embed url="<https://www.youtube.com/watch?feature=youtu.be&v=IMyKHp3iog0>" %}

### System Architecture

```
[Laptop / HMI]
     │
     │ eth0: 192.168.0.11  (www / remote access)
     │
[reComputer — OpenPLC vPLC]
  vPLC IP: 192.168.100.10
  eth1 IP: 192.168.100.2
     │
     │ Modbus TCP/IP
     │
[Balluff IO-Link Master — BNI00L3]
  IP: 192.168.100.3
     ├── Port 1 → Smart Light        (BNI IOL-812-205-K037)
     ├── Port 2 → Laser Sensor       (BOS R254K-UUI-LH10-S4)
     └── Port 3 → Condition Monitor  (BCM R15E-001-DI00-01,5-S4)
```

The vPLC connects to the IO-Link Master as a **Modbus TCP Client**, polling sensor data every scan cycle.

***

### Modbus Register Map

#### 🟢 Port 1 — Smart Light (BNI IOL-812-205-K037)

| Register No. | PLC Register | Function          |
| ------------ | ------------ | ----------------- |
| 1117         | QW0          | Smart Light State |
| 1118         | QW1          | Mode              |
| 1120 \~ 1124 | QW3 \~ QW7   | Seg1 \~ Seg5      |

***

#### 🔵 Port 2 — Laser / Photo-electric Sensor (BOS R254K-UUI-LH10-S4)

| Register No. | PLC Register | Function         |
| ------------ | ------------ | ---------------- |
| 1201         | IW10         | Object Detection |

***

#### 🟠 Port 3 — Condition Monitoring Sensor (BCM R15E-001-DI00-01,5-S4)

| Register No. | PLC Register | Function |
| ------------ | ------------ | -------- |
| 1300         | IW0          | Status   |
| 1301 \~ 1302 | IW1 \~ IW2   | X-VRMS   |
| 1303 \~ 1304 | IW3 \~ IW4   | Y-VRMS   |
| 1305 \~ 1306 | IW5 \~ IW6   | Z-VRMS   |
| 1307 \~ 1308 | IW7 \~ IW8   | Temp.    |

***

### Converting Modbus Words to REAL Float Values

The Balluff condition monitoring sensor sends each float value (e.g., X-VRMS) **split across 2 x 16-bit Modbus registers** in Big-Endian format.

To get a usable `REAL` value in OpenPLC, we need to:

1. Read the **High Word** and **Low Word** from two consecutive registers
2. **Byte-swap** them (Big-Endian → Little-Endian word order)
3. Reassemble into a **32-bit IEEE 754 float** using `memcpy`

#### 📐 Byte Swap Example

```
Register 1 (H): X-VRMS = 62    → 0x003E
Register 2 (L): X-VRMS = -9446 → 0xDB1A

Original byte order:  A  B  C  D  →  00 3E DB 1A
After word swap:      B  A  D  C  →  3E 00 1A DB

IEEE 754 interpret: 0x3E001ADB = 0.1251 g
```

#### C++ Function Block (Custom OpenPLC Extension)

This logic runs inside a **C++ Function Block** registered in OpenPLC. The `loop()` function executes every scan cycle.

```cpp
VAR_INPUT
	HighWord: uint;
	LowWord: uint;
END_VAR

VAR_OUTPUT
	RealOut: real;
END_VAR
```

```cpp
/* ================================================================
 *  C/C++ FUNCTION BLOCK
 *
 *  ---------------------------------------------------------------
 *  - This function block runs **in sync** with the PLC runtime.
 *  - The `setup()` function is called once when the block initializes.
 *  - The `loop()` function is called at every PLC scan cycle.
 *  - Block input and output variables declared in the variable table
 *    can be accessed directly by name in this C/C++ code.
 *
 *  This block executes as part of the main PLC process and follows
 *  the configured scan time in the Resources. Use it for real-time
 *  control logic, fast I/O operations, or any C-based algorithms.
 * ================================================================ */

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

void plc_log(char *msg);

int wtor_cycle_count = 0;

void setup()
{

}

void loop()
{
    uint16_t combined_array[2];
    float converted_val = 0;
    char print_msg[1000];

    uint8_t b[4];
    uint32_t u32;

    b[0] = (uint8_t)(HighWord & 0xFF);   // B = Low byte  of Register 1 (HighWord)
    b[1] = (uint8_t)(HighWord >> 8);     // A = High byte of Register 1 (HighWord)
    b[2] = (uint8_t)(LowWord  & 0xFF);   // D = Low byte  of Register 2 (LowWord)
    b[3] = (uint8_t)(LowWord  >> 8);     // C = High byte of Register 2 (LowWord)

    // placing each byte into its correct slot BADC,  b[0]=B, b[1]=A, b[2]=D, b[3]=C
    u32 = ((uint32_t)b[0] << 24) |
          ((uint32_t)b[1] << 16) |
          ((uint32_t)b[2] << 8)  |
          ((uint32_t)b[3]);

    memcpy(&RealOut, &u32, sizeof(RealOut));
    //u32 bytes = [ b0  b1  b2  b3 ] = [ B  A  D  C ]

    // Debug logs (print once every 100 cycles to avoid flooding the logs)
    if (wtor_cycle_count == 100)
    {
        sprintf(print_msg, "Low word: %02x", LowWord);
        plc_log(print_msg);
        sprintf(print_msg, "High word: %02x", HighWord);
        plc_log(print_msg);
        sprintf(print_msg, "Converted value: %f", RealOut);
        plc_log(print_msg);

        wtor_cycle_count = 0;
    }
    else
    {
        wtor_cycle_count++;
    }

}
```

> ⚠️ **Key insight:** Simply casting the INT values to REAL will give you garbage. The byte swap is mandatory because Balluff uses Big-Endian word ordering, while OpenPLC/x86 is Little-Endian.

#### C++ Print Code Function Block

```cpp
VAR_INPUT
	print_message : bool;
	content: string;
END_VAR
```

```cpp
/* ================================================================
 *  C/C++ FUNCTION BLOCK
 *
 *  ---------------------------------------------------------------
 *  - This function block runs **in sync** with the PLC runtime.
 *  - The `setup()` function is called once when the block initializes.
 *  - The `loop()` function is called at every PLC scan cycle.
 *  - Block input and output variables declared in the variable table
 *    can be accessed directly by name in this C/C++ code.
 *
 *  This block executes as part of the main PLC process and follows
 *  the configured scan time in the Resources. Use it for real-time
 *  control logic, fast I/O operations, or any C-based algorithms.
 * ================================================================ */

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

// These includes are only required by the plc_log function
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <time.h>

int log_fd = -1;
bool previous_print_msg = false;

/* ================================================================
 *  Utility function to print messages on the PLC Logs.
 * ================================================================ 
 */

void plc_log(char *msg) 
{
    if (log_fd < 0) 
    {
        struct sockaddr_un addr;
        log_fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (log_fd < 0) return;
        memset(&addr, 0, sizeof(addr));
        addr.sun_family = AF_UNIX;
        strncpy(addr.sun_path, "/run/runtime/log_runtime.socket",
                sizeof(addr.sun_path) - 1);
        if (connect(log_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) 
        {
            close(log_fd);
            log_fd = -1;
            return;
        }
    }
    char buf[512];
    snprintf(buf, sizeof(buf),
        "{\"timestamp\":\"%ld\",\"level\":\"INFO\",\"message\":\"%s\"}\n",
        (long)time(NULL), msg);
    if (write(log_fd, buf, strlen(buf)) == -1) 
    {
        close(log_fd);
        log_fd = -1;
    }
}

void setup()
{


}

void loop()
{
    if ((previous_print_msg == false) && (print_message == true))
    {
        plc_log((char *)content.body);
    }

    previous_print_msg = print_message;
}
```

***

#### Main Program

```
VAR
	wX_VRMSHighWord : uint AT %IW1;
	wX_VRMSLowWord : uint AT %IW2;
	wY_VRMSHighWord : uint AT %IW3;
	wY_VRMSLowWord : uint AT %IW4;
	wZ_VRMSHighWord : uint AT %IW5;
	wZ_VRMSLowWord : uint AT %IW6;
	wTempHighWord : uint AT %IW7;
	wTempLowWord : uint AT %IW8;
	wSensor : word AT %IW0;
	wSmartLightState : word AT %QW0;
	wMode : word AT %QW1;
	wSeg1 : word AT %QW3;
	wSeg2 : word AT %QW4;
	wSeg3 : word AT %QW5;
	wSeg4 : word AT %QW6;
	wSeg5 : word AT %QW7;
	rTemp : real;
	rX_VRMS : real;
	rY_VRMS : real;
	rZ_VRMS : real;
	WtoR_convert : WTOR;
	iVibrationState : int;
	rThresholdL : real;
	rThresholdH : real;
	rMaxVib : real;
END_VAR
```

```
//Initialized values
wSmartLightState  := 1;
wMode := 34049;
rThresholdH := 7.1;
rThresholdL := 2.5;

(* Temperature *)
WtoR_convert(HighWord := wTempHighWord, LowWord := wTempLowWord);
rTemp := WtoR_convert.RealOut;

(* X_VRMS *)
WtoR_convert(HighWord := wX_VRMSHighWord, LowWord := wX_VRMSLowWord);
rX_VRMS := WtoR_convert.RealOut;

(* Y_VRMS *)
WtoR_convert(HighWord := wY_VRMSHighWord, LowWord := wY_VRMSLowWord);
rY_VRMS := WtoR_convert.RealOut;

(* Z_VRMS *)
WtoR_convert(HighWord := wZ_VRMSHighWord, LowWord := wZ_VRMSLowWord);
rZ_VRMS := WtoR_convert.RealOut;

//Finding max Vib
(* Find max vibration *)
rMaxVib := rX_VRMS;

IF rY_VRMS > rMaxVib THEN
    rMaxVib := rY_VRMS;
END_IF;

IF rZ_VRMS > rMaxVib THEN
    rMaxVib := rZ_VRMS;
END_IF;

//Classify State
(* Classify state *)
IF rMaxVib < rThresholdL THEN
    iVibrationState := 0;

ELSIF rMaxVib > rThresholdL and rMaxVib < rThresholdH THEN
    iVibrationState := 1;

ELSE
    iVibrationState := 2;
END_IF;


IF wSensor = 1 THEN
CASE iVibrationState OF
    2: // Red Triple strobe - High vibration
    wSeg1 := 261;
    wSeg2 := 261;
    wSeg3 := 261;
    wSeg4 := 261;
    wSeg5 := 261;

    1: // Orange Rotating effect - Moderate vibration
    wSeg1 := 2055;
    wSeg2 := 2055;
    wSeg3 := 2055;
    wSeg4 := 2055;
    wSeg5 := 2055;

    ELSE // Green Stable - Low vibration 
    wSeg1 := 512;
    wSeg2 := 512;
    wSeg3 := 512;
    wSeg4 := 512;
    wSeg5 := 512;

END_CASE;

ELSE //White color, No object present
    wSeg1 := 2304;
    wSeg2 := 2304;
    wSeg3 := 2304;
    wSeg4 := 2304;
    wSeg5 := 2304;

END_IF;
```

***

### Hardware Used

| Component                     | Model                             |
| ----------------------------- | --------------------------------- |
| Edge Computer (vPLC host)     | Seeed reComputer                  |
| IO-Link Master                | Balluff BNI00L3                   |
| Smart Light                   | Balluff BNI IOL-812-205-K037      |
| Laser / Photo-electric Sensor | Balluff BOS R254K-UUI-LH10-S4     |
| Condition Monitoring Sensor   | Balluff BCM R15E-001-DI00-01,5-S4 |
| PLC Runtime                   | OpenPLC Runtime v3 (vPLC)         |

***

### Source Code

> 🔗 Source files for this project are available in the following zip file or you can access it here: <https://editor.autonomylogic.com/?project\\_id=cmmtfduw800hd07n3kzotofxv>
>
> {% file src="/files/PHBRLfnDomciHCUXTlg9" %}

***

### 🔗 Resources

* 🌐 [autonomylogic.com](https://autonomylogic.com)
* 📖 [OpenPLC Runtime Docs](https://openplcproject.com)
* 🧑‍💻 [PLC project](https://editor.autonomylogic.com/?project_id=cmmtfduw800hd07n3kzotofxv)&#x20;

{% embed url="<https://www.canva.com/design/DAHDEbIV0NU/FltviviauXtBdrJOqjFWFA/edit?utm_campaign=designshare&utm_content=DAHDEbIV0NU&utm_medium=link2&utm_source=sharebutton>" %}
Key notes
{% endembed %}

***

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# 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

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2Fo0pHqjgpI9U6wd2z59SK%2FOpenPLC%20with%20Python.mp4?alt=media&token=b2ea91e9-b8a0-4042-8b3c-f2a481afaf63>" %}

***

### 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

{% embed url="<https://www.youtube.com/watch?t=6s&v=cXp9917vTf4>" %}

***

### System Architecture

```
[OpenPLC Simulator]
        |
        |  Structured Text - sine wave generator
        |
[OpenPLC Runtime v4]
        |
        |  Python Function Block - direct variable access
        |
[Python Function Block - example_2.py]
        |
        |  HTTP POST - urllib (standard library only)
        |
[ThingsBoard Cloud - thingsboard.cloud]
        |
        -- Live temperature graph on dashboard
```

***

### 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       |

{% hint style="warning" %}
&#x20;Python FBs are NOT synchronized with the PLC scan cycle. Use standard IEC languages for real-time, time-critical control logic. Use Python for non-time-critical tasks like cloud communication.
{% endhint %}

***

### 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`

```python
from multiprocessing import shared_memory
import struct
import time
import os

def block_init():
    print('Block was initialized')

def block_loop():
    print('Block has run the loop function')
```

{% hint style="info" %}
&#x20; `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.
{% endhint %}

***

### 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.

```python
# If you declare temp_in as an Input variable in the table:
# You can read it directly in Python like this:
print(temp_in)           # reads the current PLC value

# If you declare status as an Output variable in the table:
# You can write to it directly like this:
global status           # it is mandatory to declare the variable to global
status = 1               # writes value back to PLC
```

{% hint style="info" %}
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.
{% endhint %}

***

### 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**

```rst
VAR
	simulated_temp: real;
	angle: real;
	my_inst_1: example_1;
END_VAR
```

#### **Main ST Program**

```pascal
(* Sine wave angle in radians - increments each scan cycle *)
angle := angle + 0.05;

(* Reset after full cycle - 6.283 = 2 x PI = 360 degrees *)
IF angle > 6.283 THEN
    angle := 0.0;
END_IF;

(* Generate simulated temperature - cycles between 20C and 80C *)
simulated_temp := 50.0 + (30.0 * SIN(angle));

(* Send temperature to Python FB via shared memory *)
my_inst_1(temp_in := simulated_temp);
```

#### Understanding the Sine Wave Generator

```pascal
angle := angle + 0.05;

IF angle > 6.283 
    THEN angle := 0.0; 
END_IF;

simulated_temp := 50.0 + (30.0 * SIN(angle));
```

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
VAR_INPUT
	temp_in_1 : real := 0.0;
END_VAR
```

#### **Python Code**

```python
# ================================================================
# DISCLAIMER: Python Function Block Execution
#
# This block runs asynchronously from the main PLC runtime.
# ---------------------------------------------------------------
# - All variables are shared with the runtime through shared memory.
# - The block_init() function is called once when the block starts.
# - The block_loop() function is called periodically (~100ms).
# - IMPORTANT: This periodic call DOES NOT follow the PLC scan cycle.
#   It is NOT guaranteed that block_loop() will execute once per scan.
#
# Use this block for non-time-critical tasks. For logic that must
# match the PLC scan cycle, use standard IEC 61131-3 function blocks.
# ================================================================

from multiprocessing import shared_memory
import struct
import time
import os

def block_init():
    global last_print_time   # persist across block_loop() calls
    # Record the current time as the starting reference point
    last_print_time = time.time()
    print('Python FB started!')

def block_loop():
    global last_print_time   # must redeclare global in every function that uses it
    now = time.time()

    # Only print every 2 seconds - avoids flooding the PLC Logs
    if now - last_print_time >= 2.0:
        last_print_time = now  # reset the timer
        #print(f'Temperature: {round(temp_in_1, 2)} C')

```

**PLC Logs Output**

```
Python FB started!
Temperature: 62.35 C
Temperature: 71.18 C
Temperature: 78.43 C
Temperature: 79.98 C
```

***

### 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**&#x20;

```python
VAR_INPUT
	temp_in_2 : real := 0.0;
END_VAR

VAR_OUTPUT
	status: int;
END_VAR
```

#### **ThingsBoard Cloud Setup**

1. Sign up for free at [thingsboard.cloud](https://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:

```
'https://thingsboard.cloud/api/v1/YOUR_TOKEN/telemetry'
```

#### **Python FB Code**

```python
# ============================================================
# Example 2: OpenPLC Python FB - ThingsBoard Cloud Telemetry
# Reads simulated temperature from PLC via shared memory
# Sends to ThingsBoard Cloud via HTTP every 5 seconds
# Writes connection status back to PLC via shared memory
# ============================================================

from multiprocessing import shared_memory
import struct
import time
import os

import urllib.request
import json

# ThingsBoard Cloud endpoint curl -v -X POST http://thingsboard.cloud/api/v1/K4GHZZMJY2zsnvesTDm8/telemetry --header Content-Type:application/json --data "{temperature:25}"
URL = 'https://thingsboard.cloud/api/v1/3JOfPb6SZUURbfIkVVId/telemetry'

#  HTTP Send Function 
def send_to_thingsboard(payload):
    try:
        req = urllib.request.Request(
            URL,
            data=payload.encode('utf-8'),
            headers={'Content-Type': 'application/json'}
        )
        urllib.request.urlopen(req, timeout=3)
        print('Sent: ' + payload)
        return True
    except Exception as e:
        print('Error: ' + str(e))
        return False

#  Called ONCE on startup ============================================================
def block_init():
    global last_send_time, status

    # Wait 5 seconds before first send (let runtime stabilise)
    last_send_time = time.time() + 5
    status = 0
    print('Cloud FB started!')

#  Called EVERY ~100ms ============================================================
def block_loop():
    global last_send_time, status

    # Only send every 5 seconds
    if time.time() - last_send_time < 5.0:
        return
    last_send_time = time.time()

    payload = json.dumps({'temperature': round(float(temp_in_2), 2)})
    success = send_to_thingsboard(payload)

    # WRITE: status 
    status = 1 if success else 0
```

#### **Main ST Program**

**Variable Table**

```rst
VAR
	simulated_temp : real;
	angle : real;
	my_inst_1 : example_1;
	my_inst_2 : example_2;
	sent_status : int;
END_VAR
```

**Main ST Program**

```pascal
(* Sine wave angle in radians - increments each scan cycle *)
angle := angle + 0.05;

(* Reset after full cycle - 6.283 = 2 x PI = 360 degrees *)
IF angle > 6.283 THEN
    angle := 0.0;
END_IF;

(* Generate simulated temperature - cycles between 20C and 80C *)
simulated_temp := 50.0 + (30.0 * SIN(angle));

my_inst_2(temp_in_2 := simulated_temp);
sent_status := my_inst_2.status;
```

***

### 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.

```python
# WRONG - triggers on loop 0 before runtime is stable
if loop_counter % 50 == 0:

# CORRECT - waits true 5 seconds from stable init
if time.time() - last_send_time >= 5.0:
```

#### **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()`:

```python
def block_init():
    global last_send_time, status   # declare and initialise here
    last_send_time = time.time() + 5
    status = 0

def block_loop():
    global last_send_time, status   # redeclare in every function that uses it
    status = 1 if success else 0
```

#### **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

{% embed url="<https://canva.link/5i0q4niwcochp5f>" %}

### 🔗 Resources

* 🌐 Open PLC editor and Runtime: [autonomylogic.com](https://autonomylogic.com)
* 📖 [Python FB Documentation](https://edge.autonomylogic.com/docs/openplc-editor/custom-languages/python-blocks/python-basics)
* 📊 [ThingsBoard Cloud](https://thingsboard.cloud)
* 🧑‍💻 [Code Compile](https://codeandcompile.com)

***

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# OTee- Open Architecture Real time Virtual PLCs

In this article, we’ll show you a step-by-step live demo of deploying a fully functional Virtual PLC using OTee.io and a Revolution Pi as the edge device.

## Virtual PLC made Easy using OTee

### What is Virtual PLC?

* **Virtual PLCs** are software-based controllers that perform PLC operations on **general-purpose hardware** like **Linux systems**, enabling **flexible deployment** and easy management.
* **OTee.io** is a **free platform** for creating and deploying virtual PLCs, supporting **IEC 61131-3 programming**, **Modbus TCP I/Os**, and **Linux-based edge devices** like Revolution Pi.

## Video Review

{% embed url="<https://www.youtube.com/watch?t=778s&v=zOd3gzlpits>" %}

### Programming and Deployment

* OTee's **structure text editor** allows for efficient PLC programming using **IEC 61131-3 compliant language**, featuring **tag definition**, **variable creation**, **logic programming**, and **alarm creation**.
* The **onboarding process** for OTee involves adding a device, downloading an installer, running it on the edge device, and installing the **OTee agent** for real-time data exchange between the cloud and edge.

### Communication and Monitoring

* **Modbus communication** in OTee enables connecting Virtual PLCs to a **Modbus server** on a computer, allowing **remote monitoring** and control of field I/O devices like temperature sensors.
* The **tag browser** in OTee facilitates remote editing and modification of tags, including temperature and heater values, for real-time troubleshooting and visualization of PLC program behavior.

### Platform Features and Benefits

* OTee provides a **centralized secure cloud environment** for managing Virtual PLCs, offering **role-based access control**, **industrial-grade open runtime**, **hardware agnosticism**, and **fleet management**.
* **CI/CD pipelines** and **community-driven libraries** in OTee enable error-free testing and deployment of PLC programs, promoting **open innovation** and collaboration in industrial automation.

## Key notes:

{% embed url="<https://www.canva.com/design/DAGt0tNMrTw/ZvKx3Ovwzuz_M5T_G-WGoA/view?utlId=hff46ff4ec4&utm_campaign=designshare&utm_content=DAGt0tNMrTw&utm_medium=link2&utm_source=uniquelinks>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# OTee Docker Commands

Quick reference

A handy reference for managing an OTee edge deployment (the vPLC agent + NATS) with Docker on a Linux edge device.

> **Note on names:** OTee's compose project and containers are named per device (e.g. `agent_<device>`, `nats-nats_<device>`, `agent-agent_<device>`). Run `docker ps -a` to see the exact names on your machine, and substitute them below.

## Check status

```bash
docker ps                       # running containers
docker ps -a                    # all containers, including stopped ones
docker images                   # installed images
docker volume ls                # volumes
docker logs <container> --tail 50          # last 50 log lines
docker logs <container> --tail 50 -f       # follow logs live
```

## Start, stop, restart

```bash
docker compose -p <project> up -d           # start the stack (detached)
docker compose -p <project> down            # stop + remove containers & network
docker compose -p <project> restart         # restart in place
```

**Tip:** `restart` reuses the existing container environment. If you've changed config or timezone, use `down` then `up -d` so the change is actually picked up.

## Run Docker without sudo

If Docker asks for `sudo`, your user isn't in the docker group yet:

```bash
sudo usermod -aG docker $USER
```

Then log out and back in (or reboot) for it to take effect.

## Full clean wipe (for a fresh install)

**Order matters**- remove containers *before* images. Stopped containers still hold image references, so `docker rmi` fails if you skip the container removal step.

```bash
# 1. Bring the stack down
docker compose -p <project> down

# 2. Force-remove any lingering containers
docker rm -f <nats-container> <agent-container>

# 3. Remove images (only works once the containers are gone)
docker rmi <agent-image> <nats-image>

# 4. Remove the volume (wipes runtime state)
docker volume rm <volume-name>
```

Verify it's clean:

```bash
docker ps -a && docker images && docker volume ls
```

## Install Docker (Debian-based devices)

```bash
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER      # then log out/in
```

## Troubleshooting a container that won't start

```bash
docker logs <container> --tail 50
```

Check the logs first, most start-up failures point to their cause there. If the container relies on time-sensitive services, make sure the device clock is synced (`timedatectl` / `chronyc tracking`) before retrying.


# HiveMQ

This section brings together a set of practical reference architectures showing how HiveMQ is commonly used in industrial OT/IT environments.

Each page builds on the previous one, from simple **PLC-to-cloud flows** to **enterprise-grade, secure OT/IT integration.**

You can use these guides to:

* Understand how HiveMQ fits into typical industrial architectures
* Design scalable MQTT / UNS-based data pipelines
* Explain OT/IT integration concepts to engineers, IT teams, and management

<figure><img src="/files/3rFIXvIpTWWBSrQwEMuC" alt=""><figcaption></figcaption></figure>

#### What you’ll find in the sub-pages

* [PLC to Cloud via HiveMQ (Edge + Cloud) — OPC UA → MQTT → Confluent](/product-reviews/smart-platforms/hivemq/plc-to-cloud-via-hivemq-edge-+-cloud-opc-ua-mqtt-confluent)\
  A foundational flow showing how PLC data is collected via OPC UA, mapped to MQTT using HiveMQ Edge, and forwarded to cloud systems.
* [Multi-Site PLC-to-Cloud Flow using HiveMQ Edge + Cloud](/product-reviews/smart-platforms/hivemq/multi-site-plc-to-cloud-flow-using-hivemq-edge-+-cloud)\
  An extension of the basic pattern, demonstrating how multiple sites and Edge instances can feed a centralized cloud or enterprise broker.
* [HiveMQ Edge-to-Cloud AI Pipeline](/product-reviews/smart-platforms/hivemq/hivemq-edge-to-cloud-ai-pipeline)\
  A use-case-driven example showing how OT data can be consumed by analytics and AI workloads once it is available via MQTT.
* [Secure OT/IT Data Integration Using HiveMQ Edge and Site DMZ](/product-reviews/smart-platforms/hivemq/secure-ot-it-data-integration-using-hivemq-edge-and-site-dmz)\
  A reference architecture illustrating how enterprises typically separate OT and IT using a Site DMZ (Level 3.5), with HiveMQ Edge and brokers deployed in layers.

Together, these pages provide a **progressive learning path** — from simple connectivity to enterprise-ready OT/IT integration aligned with UNS and security best practices.

{% hint style="info" %}
Each article is intentionally architecture-focused and vendor-neutral, reflecting how HiveMQ is deployed in real industrial environments.
{% endhint %}


# PLC to Cloud via HiveMQ (Edge + Cloud) — OPC UA → MQTT → Confluent

Read PLC via OPC UA, map to MQTT with HiveMQ Edge, bridge to HiveMQ Cloud, and stream to Confluent (Kafka).

**Sending PLC data to Cloud (Kafka) makes machine data available in real-time for dashboards, analytics, and cloud applications.** It keeps the PLC focused on control, while Kafka distributes the data to multiple systems simultaneously.

<figure><img src="/files/Z5TbyAa2dg519ziJhCme" alt=""><figcaption></figcaption></figure>

## Why send PLC data to Cloud (Kafka)?

PLC data (temperatures, counts, states, and alarms) is valuable, but PLCs are designed for machine control, not for handling large amounts of data or integrating with cloud systems.

By streaming PLC data into **Kafka** (via HiveMQ), you get:

* **Scalability** – Kafka can handle millions of events per second from many PLCs and machines.
* **Integration** – Kafka acts as a hub, making PLC data accessible to cloud applications, analytics platforms, databases, AI/ML pipelines, and more.
* **Real-time processing** – Process machine data as it happens (predictive maintenance, quality checks, dashboards).
* **Decoupling** – PLCs stay focused on control, while Kafka distributes the data to any number of consumers without overloading the PLC.

👉 In short: **Kafka turns raw PLC data into a real-time data stream for enterprise systems and analytics.**

## Information flow

### 1. Read PLC data via OPC UA

First, we read raw data from the Siemens S7-1500 PLC via OPC UA. The Siemens PLC acts as an OPC UA server, and the Edge device acts as an OPC UA client. The Revolution Pi acts as an Edge device, running HiveMQ Edge —a software-based Edge MQTT Gateway that features several protocol adaptors. We use an OPC UA adaptor that reads directly from the Siemens S7-1500 PLC.&#x20;

<figure><img src="/files/nx6cxGVpRXqpAtJgOpFe" alt="" width="563"><figcaption><p>LIVE Tag value in TIA Portal Online view</p></figcaption></figure>

<figure><img src="/files/mK4WzAIPbSeHAJIDbyE5" alt="" width="563"><figcaption><p>Configuration of OPC UA tag in HiveMQ Edge</p></figcaption></figure>

### 2. Data mapping

Map OPC UA tags to MQTT topics in HiveMQ Edge, which means now we have the data streaming to the defined MQTT topic of the MQTT broker running locally in the Revolution Pi.

<figure><img src="/files/fFRI5hJasZ7BJOBODXSW" alt="" width="563"><figcaption><p>Data mapping from OPC UA to MQTT in HiveMQ Edge</p></figcaption></figure>

### 3. MQTT Bridge

HiveMQ Edge bridges the **local MQTT broker (located on the Edge) to the HiveMQ Cloud broker, enabling the global sharing of data** via a secure network.

<figure><img src="/files/vI2WxNGE8CkaFR9WqMqz" alt="" width="563"><figcaption><p>Local MQTT Broker --> Cloud MQTT Broker in HiveMQ Edge</p></figcaption></figure>

### 4. Topic Filter

To bridge the data from the local MQTT broker to the Cloud MQTT broker, we need to add a topic filter to the MQTT Bridge connection.&#x20;

<figure><img src="/files/K3OA7uTO4x37mivQA96I" alt="" width="375"><figcaption></figcaption></figure>

Using the filter as shown above will send the data to the Cloud MQTT Broker with the same topic as declared in the local MQTT broker, as shown below:

<figure><img src="/files/BsvrxBOhx6b0gjp21yFL" alt=""><figcaption></figcaption></figure>

### 5. HiveMQ Cloud to Kafka

HiveMQ Cloud forwards MQTT messages to Kafka topics (Confluent) using the Kafka protocol, with a ready-to-use integration in the platform. HiveMQ Cloud’s **Confluent/Kafka integration** forwards MQTT messages to Kafka **using the Kafka protocol**, not MQTT.

<figure><img src="/files/0tnJYX1KU1EvOTMuUML8" alt="" width="563"><figcaption><p>Bootstrap server link of the Cluster in Confluent</p></figcaption></figure>

<figure><img src="/files/oLXij5cZLLuHRSefj0gS" alt="" width="563"><figcaption><p>Api Key and secret of Cluster in Confluent</p></figcaption></figure>

<figure><img src="/files/fF1wTB9tE0hUNIOPxlmj" alt="" width="563"><figcaption><p>MQTT Topic --> Kafka Topic in HiveMQ Cloud</p></figcaption></figure>

## How to install HiveMQ Edge in Revolution Pi?

{% stepper %}
{% step %}
Download the HiveMQ Edge package in Revolution Pi.

```sh
#move to opt directory
cd /
cd opt
#download the HiveMQ package
sudo curl -O https://www.hivemq.com/releases/edge/hivemq-edge-full-2025.15.zip
```

{% endstep %}

{% step %}
Install Java (if not installed)

```sh
sudo apt update
sudo apt install -y openjdk-17-jre-headless
```

{% endstep %}

{% step %}
Install unzip (if not pre-installed)

```sh
sudo apt update
sudo apt install unzip -y
```

{% endstep %}

{% step %}
Unzip the package

```sh
sudo unzip hivemq-edge-full-2025.15.zip
```

{% endstep %}

{% step %}
Create a HiveMQ symbolic link (symlink):

```sh
sudo ln -s /opt/hivemq-edge-full-2025.15 /opt/hivemq
```

{% endstep %}

{% step %}
Create a HiveMQ user:

```sh
sudo useradd -d /opt/hivemq hivemq
```

{% endstep %}

{% step %}
Make scripts executable and change the owner to the hivemq user:

```sh
sudo chown -R hivemq:hivemq /opt/hivemq-edge-2025.15
sudo chown -R hivemq:hivemq /opt/hivemq
cd /opt/hivemq-edge-2025.15
sudo chmod +x ./bin/run.sh
```

{% endstep %}

{% step %}
Install the init script (optional). For Debian-based Linux distributions such as Debian, Ubuntu, or Raspbian that use init.d scripts:

```sh
sudo cp /opt/hivemq/bin/init-script/hivemq-debian /etc/init.d/hivemq
sudo chmod +x /etc/init.d/hivemq
```

{% endstep %}

{% step %}
Start HiveMQ on boot (optional)

```sh
sudo systemctl enable hivemq
```

{% endstep %}

{% step %}
Start HiveMQ

```sh
cd /opt/hivemq-edge-2025.15
sudo ./bin/run.sh
```

{% endstep %}

{% step %}
Log in to HiveMQ Edge Web UI

Once you start a HiveMQ Edge instance, you can access the HiveMQ Edge administrative console in your Edge device browser at [http://localhost:8080](http://localhost:8080/). The default username is "admin", and the default password is "hivemq".\
\
If you want to view the Web UI on your computer remotely, you can set up an SSH Tunnel. In your computer, run the following code in the terminal

```sh
ssh -L 8080:localhost:8080 pi@192.168.0.109
```

{% endstep %}
{% endstepper %}

{% hint style="success" %}

## Now you can access the HiveMQ Edge Web UI by opening localhost:8080. Log in usingthe  default credentials, username: admin and password: hivemq

{% endhint %}

<figure><img src="/files/nDWwhLrsEvPnxsWdyOnf" alt="" width="563"><figcaption><p>WebUI of HiveMQ Edge running in Revolution Pi</p></figcaption></figure>

## Abbreviations & Terms

* **OPC UA (Open Platform Communications – Unified Architecture)**\
  A machine-to-machine communication protocol for industrial automation. Used to read/write real-time data from PLCs, sensors, and devices.
* **MQTT (Message Queuing Telemetry Transport)**\
  A lightweight publish/subscribe messaging protocol, ideal for IoT devices and edge communication.
* **Edge Device**\
  A device placed close to machines (e.g., Revolution Pi) that collects and forwards data, often translating from one protocol to another.
* **HiveMQ**\
  HiveMQ is the proven MQTT IoT data streaming platform for secure, real-time data connectivity, enabling more intelligent decisions and digital transformation. Learn more [here](https://www.hivemq.com/)
* **HiveMQ Edge / HiveMQ Cloud**
  * **HiveMQ Edge**: Runs locally (on Raspberry Pi / RevPi) to connect industrial protocols, such as OPC UA, to MQTT.
  * **HiveMQ Cloud**: Managed MQTT broker in the cloud, used for scalable IoT data exchange.
* **Kafka (Apache Kafka)**\
  It’s basically a **high-performance message bus** that can handle millions of messages per second. It’s used to **publish, store, process, and subscribe** to streams of events (such as sensor data, logs, and transactions).&#x20;
* **Confluent**\
  A managed cloud service built on Apache Kafka, providing Kafka clusters plus enterprise features like security, monitoring, and connectors. So instead of running Kafka yourself (which can be complex), you can use Confluent’s hosted Kafka clusters.

## Debug

* No javaruntime installed error!

```sh
sudo apt update
sudo apt install -y openjdk-17-jre-headless
```

* Port 1883 occupied

```sh
sudo netstat -tulpn | grep :1883
#You will get output like this
#tcp   LISTEN   0   128   0.0.0.0:1883   0.0.0.0:*   1234/mosquitto
sudo kill -9 1234 #kill service with specific PID

```

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Multi-Site PLC-to-Cloud Flow using HiveMQ Edge + Cloud

Connecting industrial PLCs securely from multiple sites to the cloud has never been this simple.

In this guide, we’ll see how **HiveMQ Edge** and **HiveMQ Cloud** can be used together to bridge data from Siemens and Allen-Bradley PLCs — using **OPC UA**, **Modbus TCP**, and **MQTT**.

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2F7sqPgX9ygJtGSuymuBBv%2FPost%202.mp4?alt=media&token=caa21492-c932-446a-9466-dfbcca7822c6>" %}

## System Overview

This setup demonstrates a **multi-site architecture**:

* **Site A**: Process running with Siemens S7-1500 PLC&#x20;
* **Site B**: Process running with Allen-Bradley Micro850 PLC
* Both sites send local PLC data to **HiveMQ Edge**
  * **Site A**: Siemens S7-1500 PLC via OPC UA
  * **Site B**: Allen-Bradley Micro850 PLC via Modbus TCP
* A secure **MQTT Bridge on HiveMQ Edge** transfers data from the Edge devices to the **HiveMQ Cloud**

### Step 1 – Connect PLCs to HiveMQ Edge and assign a local MQTT Topic

<div data-full-width="true"><figure><img src="/files/UA3OEWswq3fDitkBnxOi" alt=""><figcaption><p>LIVE data in the S7-1500 PLC</p></figcaption></figure></div>

<figure><img src="/files/suo8abhnWXNpETz4NHoo" alt=""><figcaption><p>LIVE data in the Micro850 PLC</p></figcaption></figure>

#### a) Siemens S7-1500 (OPC UA)

Install HiveMQ in the edge device. In this case, we are using Revolution Pi as an edge device where HiveMQ Edge has been installed.

{% hint style="success" %}
To learn more about how to install HiveMQ Edge on the edge device, check out this [page](/product-reviews/smart-platforms/hivemq/plc-to-cloud-via-hivemq-edge-+-cloud-opc-ua-mqtt-confluent).
{% endhint %}

**Navigate to the HiveMQ Edge → Protocol Adapters**, add a new **OPC UA Protocol Adapter**.\
Configure the connection details of your S7-1500 using the OPC UA endpoint, and select the OPC UA tag.

<figure><img src="/files/zdJiCHdmu6Wt2RWzOKZ9" alt=""><figcaption></figcaption></figure>

Then create a **northbound mapping** to publish it as:

```
Topic: machine/s71500/rTemp
```

<figure><img src="/files/F9AhG4E1HlMMS9vBAy6I" alt=""><figcaption></figcaption></figure>

This allows HiveMQ Edge to read OPC UA values and push them to the local MQTT broker.

#### b) Allen-Bradley Micro850 (Modbus TCP/IP)

Similarly, install HiveMQ in another edge device. In this case, we are using a reComputer from Seeed Studio as an edge device where HiveMQ Edge has been installed.

{% hint style="success" %}
To learn more about how to install HiveMQ Edge on the edge device, check out this [page](/product-reviews/smart-platforms/hivemq/plc-to-cloud-via-hivemq-edge-+-cloud-opc-ua-mqtt-confluent).
{% endhint %}

Add a **Modbus Protocol Adapter** and connect to the Micro850 PLC via MODBUS TCP/IP.

<figure><img src="/files/6cCthMjBJIYXn9FWEUjD" alt=""><figcaption></figcaption></figure>

Select the tag `Current_Temp` and map it to the following topic:

```
Topic: machine/micro850/rTemp
```

<figure><img src="/files/nMUNvI1olGXp17jQRCV8" alt=""><figcaption></figcaption></figure>

Each tag update will now be converted to MQTT messages locally.

### Step 2 – Creating the MQTT Bridge

In both **HiveMQ Edge → MQTT Bridges**, create a bridge to your **HiveMQ Cloud Cluster**.\
Once connected, data from both sites is securely forwarded to the cloud broker.

<figure><img src="/files/ySLePWVEjr0nDBds7vTq" alt=""><figcaption><p>MQTT bridge in Revolution Pi</p></figcaption></figure>

<figure><img src="/files/Jy17hxOGY5DTWHUyGnL4" alt=""><figcaption><p>MQTT bridge in reComputer</p></figcaption></figure>

### Step 4 – Visualizing Data on HiveMQ Cloud

Log in to your **HiveMQ Cloud Web Client**, subscribe to your topic (e.g., `#`), and you’ll start receiving live messages as shown below:

<figure><img src="/files/1uLIQgqpL6fu45qvUyEH" alt=""><figcaption></figcaption></figure>

You can now view, analyze, and integrate these values into dashboards or data platforms.

***

### 🧠 Step 5 – Understanding the Data Flow

From each PLC:

* Data is read using **OPC UA** or **Modbus TCP**
* HiveMQ Edge maps the tags to MQTT topics
* The **MQTT Bridge** sends this data securely to **HiveMQ Cloud**

✅ Supports multiple sites\
✅ Secure TLS connection\
✅ Cloud-ready and scalable

### 🧩 Why HiveMQ Cloud?

* 🔒 Secure MQTT Bridge
* 🌐 Multi-site scalability
* ☁️ Cloud-ready architecture
* 💡 Perfect bridge between OT and IT

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# HiveMQ Edge-to-Cloud AI Pipeline

Anomaly Detection using HiveMQ Cloud, Python (PyOD), and Flask

This article explains the full data pipeline shown in the diagram starting from a PLC on the shopfloor, sending data through HiveMQ Edge and Cloud, into an AI model built with **Python + PyOD**, and finally sending the anomaly result back to the HiveMQ Edge for visualization.

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FN7nrvFnAq1yuJpxLOFcm%2FHiveMQ_Post3.mp4?alt=media&token=fdabc463-593a-40d1-9092-f67facd0188d>" %}

{% hint style="info" %}
Kindly refer to last article to learn how to send factory data to HiveMQ Cloud. This article continues from there to further send data to ML for anomaly detection.
{% endhint %}

## System Overview

This architecture demonstrates how vibration data from a machine is collected at the **OT (Operational Technology)** level, transported securely to the **Cloud**, evaluated using an AI model, and returned to the shop-floor for further action.

It consists of:

1. **Input Layer** – Reading vibration data from a PLC (via OPC UA)
2. **Transport Layer** – Sending data from HiveMQ Edge → HiveMQ Cloud (via MQTT)
3. **AI Layer** – ML server running Python + Flask + PyOD locally on the computer
4. **Output Layer** – Returning anomaly alerts via MQTT → HiveMQ Edge → PLC (optional)

***

## Step-by-Step Breakdown of the Pipeline

### **1. Input Layer — PLC to HiveMQ Edge (OPC UA)**

* A Siemens S7-1500 PLC measures **vibration (simulated)** from the machine.
* This data is exposed through **OPC UA**.
* HiveMQ Edge connects to the PLC's OPC UA server.
* It maps the OPC UA tag (e.g., `vibration`) to an MQTT topic:

```
machine/s71500/rVib
```

> Industrial data becomes IIoT data.

***

### **2. Transport Layer — HiveMQ Edge to HiveMQ Cloud (MQTT)**

HiveMQ Edge publishes the MQTT message (`machine/s71500/vib`) to **HiveMQ Cloud**, which acts as a central cloud broker.

Benefits:

* Low latency
* Very small message size → suitable for industrial IoT
* Secure TLS transport and easy to scale

{% hint style="info" %}
Learn more about that in our earlier posts on HiveMQ where you will learn the complete workflow: [PLC to Cloud via HiveMQ (Edge + Cloud) — OPC UA → MQTT → Confluent](/product-reviews/smart-platforms/hivemq/plc-to-cloud-via-hivemq-edge-+-cloud-opc-ua-mqtt-confluent)
{% endhint %}

***

### 3. AI Layer — ML server running Python + Flask + PyOD locally on the compute

This is where the anomaly detection happens. Let's first understand what is Anomaly detection and why we need it

#### What is Anomaly detection?

**Anomaly detection** is the process of identifying data points or behavior that deviate from what’s considered *normal*. In simple terms, it spots when something unusual is happening.

In **Machine Learning**, anomaly detection helps models understand patterns and flag unexpected behaviour without needing labels. In **IIoT**, it's essential because machines generate huge amounts of real-time data, and even small deviations can signal issues like equipment failure, quality defects, cyber-attacks, or unsafe operating conditions.

#### **Why we need it:**

* Detect problems early before they become costly
* Improve uptime and reliability
* Enhance safety and Reduce maintenance costs

#### 🧠 PyOD — Python Outlier Detection Library

**PyOD** is a widely-used ML library that provides 40+ algorithms for anomaly detection, such as:

* Isolation Forest (IForest)
* AutoEncoders
* One-Class SVM
* LOF (Local Outlier Factor)

In the example, **Isolation Forest (IForest)** is used. It learns what “normal vibration” looks like from training data:

```python
train = np.array([[0.23], [0.25], [0.21], [0.29]])
model = IForest()
model.fit(train)
```

When new data comes, PyOD predicts:

* **0 → Normal**
* **1 → Anomaly**

**Learn more about Pyod here:** [**https://pyod.readthedocs.io/en/latest/**](https://pyod.readthedocs.io/en/latest/)

#### **Installing Pyod and testing Anomaly detection**

In our example, the Pyod has been installed in the windows computer. The following are the steps:

{% stepper %}
{% step %}

#### Install pyod on Windows PC

{% hint style="info" %}
Make sure Python is installed in your computer. In our case, we are using Python 3. To install Python visit here: <https://www.python.org/downloads/>
{% endhint %}

```
pip3 install pyod
```

{% endstep %}

{% step %}

#### Create a python file for testing:

`test_pyod.py`
{% endstep %}

{% step %}

#### Add the following code in that

```python
from pyod.models.iforest import IForest
import numpy as np

# training data: only normal vibration history
train = np.array([[0.23], [0.25], [0.21], [0.29]])

model = IForest()
model.fit(train)

# real-time vibration input
value = 0.45 #change this value to see different result.
prediction = model.predict([[value]])[0]

if prediction == 1:
    print("Anomaly detected!")
else:
    print("Normal")

```

{% endstep %}

{% step %}

#### Run the Python file

```shellscript
python test_pyod.py
```

{% endstep %}

{% step %}

#### Validate the output

‘Anomaly detected’ or ‘Normal’ based on the value sent in the code (0.45)
{% endstep %}
{% endstepper %}

#### Anomaly detection using Pyod and Node-RED

Now, we are going to test the code using Node-RED. In this case, we setup a flask server in Node-RED so that we can execute the Python code using API. This makes it easy to send data to the Python file and get anomaly results as feedback.

{% hint style="info" %}
Make sure latest version of Node-RED and Python is installed in your system.&#x20;

* To install Node-RED visit here: <https://nodered.org/>
* To install Python visit here: <https://www.python.org/downloads/>
  {% endhint %}

Once, the Node-RED is installed proceed with the following steps:

{% stepper %}
{% step %}

#### Convert Your Python Code into a Simple API Server.

We will not run Python file directly from Node-RED, we will create a Python web API for data exchange.&#x20;

Create a new Python file named '**server.py**' with the following code:

{% code overflow="wrap" lineNumbers="true" expandable="true" %}

```python
from flask import Flask, request, jsonify
from pyod.models.iforest import IForest
import numpy as np

app = Flask(__name__)

# Train model once at startup
train = np.array([[0.23], [0.25], [0.21], [0.29]])
model = IForest()
model.fit(train)

@app.route("/predict", methods=["POST"])
def predict():
    data = request.json
    value = float(data["value"])  # vibration input

    prediction = model.predict([[value]])[0]

    return jsonify({
        "value": value,
        "prediction": int(prediction),
        "status": "Anomaly" if prediction == 1 else "Normal"
    })

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
```

{% endcode %}
{% endstep %}

{% step %}

#### Install Flask

```shellscript
pip install flask
```

{% endstep %}

{% step %}

#### Run your Python Server

```shellscript
python server.py
```

{% endstep %}

{% step %}

#### Validate

You should see the following:

<figure><img src="/files/zMyDf7tFLRaaojkKEtiA" alt=""><figcaption></figcaption></figure>

Your anomaly detection API is now LIVE at: <http://localhost:5000/predict>
{% endstep %}

{% step %}

#### Start Node-RED and test the Anomaly detection

You can use the '**http request node**' in Node-RED to send sample data and fetch anomaly results as shown below.&#x20;

<figure><img src="/files/7XhteKdDw8faP3PWJeij" alt=""><figcaption></figcaption></figure>

Kindly check the reference Node-RED flow below:

{% code overflow="wrap" expandable="true" %}

```json
[
    {
        "id": "53bf0f485d74978b",
        "type": "tab",
        "label": "Flow 3",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "05ded4d2341631a0",
        "type": "http request",
        "z": "53bf0f485d74978b",
        "name": "",
        "method": "POST",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://localhost:5000/predict",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 530,
        "y": 80,
        "wires": [
            [
                "7b1ef153885b1894"
            ]
        ]
    },
    {
        "id": "4abe4b4dca5e520e",
        "type": "function",
        "z": "53bf0f485d74978b",
        "name": "function 3",
        "func": "msg.headers = { \"Content-Type\": \"application/json\" };\nmsg.payload = { value: msg.payload };\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 340,
        "y": 80,
        "wires": [
            [
                "05ded4d2341631a0"
            ]
        ]
    },
    {
        "id": "7b1ef153885b1894",
        "type": "debug",
        "z": "53bf0f485d74978b",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 700,
        "y": 80,
        "wires": []
    },
    {
        "id": "301488acacb31208",
        "type": "inject",
        "z": "53bf0f485d74978b",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "0.45",
        "payloadType": "num",
        "x": 150,
        "y": 80,
        "wires": [
            [
                "4abe4b4dca5e520e"
            ]
        ]
    },
    {
        "id": "0f591249346fc88a",
        "type": "inject",
        "z": "53bf0f485d74978b",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "0.25",
        "payloadType": "num",
        "x": 150,
        "y": 120,
        "wires": [
            [
                "4abe4b4dca5e520e"
            ]
        ]
    }
]
```

{% endcode %}
{% endstep %}
{% endstepper %}

***

#### Testing Anomaly detection with PLC Data

Now, let's use the above example and sends the PLC data to the Python server to get anomaly results.&#x20;

{% hint style="info" %}
For the sake of demonstration, we are considering the normal values within the range $$0.0∼5.0$$ and anomalies outside this range. So, in our Python code, we have created a dataset of $$500$$ samples in the range of $$0.0$$ to $$5.0$$. Our model will learn from this dataset, as shown in the code below.
{% endhint %}

{% stepper %}
{% step %}

#### Update your Python code in the server.py file

The code trains an anomaly detection model, exposes it through a REST API, and lets you retrain the model using real machine data.

{% code overflow="wrap" lineNumbers="true" expandable="true" %}

```python
from flask import Flask, request, jsonify
from pyod.models.iforest import IForest
from sklearn.preprocessing import StandardScaler
import numpy as np

app = Flask(__name__)

# =========================================================
# 1. TRAIN MODEL ON REALISTIC NORMAL VIBRATION DISTRIBUTION
# =========================================================

# Simulate "normal" vibration: around 2.0 + noise(-3 to +3)
# That gives ~ 0 to 5 mm/s range
normal_values = np.random.uniform(0.0, 5.0, 500)   # 500 samples
normal_values = normal_values.reshape(-1, 1)

# Scale the training data (important for broader vibration ranges)
scaler = StandardScaler()
normal_scaled = scaler.fit_transform(normal_values)

# Train Isolation Forest
model = IForest(contamination=0.05)  # 5% anomaly expected
model.fit(normal_scaled)


# =========================================================
# 2. API ENDPOINT: PREDICT ANOMALY
# =========================================================
@app.route("/predict", methods=["POST"])
def predict():
    data = request.json
    value = float(data["value"])

    # Scale incoming data
    scaled_value = scaler.transform([[value]])

    # Raw prediction: 1 = anomaly, 0 = normal
    prediction = int(model.predict(scaled_value)[0])

    # Anomaly score (higher → more anomaly)
    score = float(model.decision_function(scaled_value)[0])

    return jsonify({
        "input_value": value,
        "scaled_value": scaled_value[0][0],
        "anomaly_score": score,
        "prediction": prediction,
        "status": "Anomaly Detected" if prediction == 1 else "Normal Behaviour"
    })


# =========================================================
# 3. OPTIONAL — RETRAIN USING DATA FROM CLIENT (Node-RED)
# =========================================================
@app.route("/retrain", methods=["POST"])
def retrain():
    data = request.json
    new_samples = np.array(data["samples"]).reshape(-1, 1)

    global scaler, model

    scaler = StandardScaler()
    scaled = scaler.fit_transform(new_samples)

    model = IForest(contamination=0.05)
    model.fit(scaled)

    return jsonify({"message": "Model retrained successfully", "samples_used": len(new_samples)})


# =========================================================
# 4. RUN SERVER
# =========================================================
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

```

{% endcode %}

This script creates a small **AI-powered anomaly detection API** using Flask and the PyOD Isolation Forest model.

1. **It generates normal vibration data** (0–5 mm/s) and uses it to train an Isolation Forest model.
2. **It scales all vibration values** using StandardScaler so the model can understand them correctly.
3. **It exposes a `/predict` API endpoint** where you send one vibration value, and the server returns:
   * Normal or Anomaly
   * Anomaly score
   * Scaled value
4. **It provides a `/retrain` endpoint** that allows you to send new vibration samples (from Node-RED or a PLC) and retrain the model on the fly.
5. **Flask runs the server on port 5000**, making it easy to integrate with IIoT systems.

Learn more about this code here: [Anomaly detection Code Explanation](/product-reviews/smart-platforms/hivemq/hivemq-edge-to-cloud-ai-pipeline/anomaly-detection-code-explanation)&#x20;
{% endstep %}

{% step %}

#### Update the Node-RED flow

Now we need to subscribe the following HiveMQ Cloud topic to get the LIVE vibration data:

```
hivemq-edge/machine/s71500/rVib
```

<figure><img src="/files/M6ovmudQeJq1mKxjt6Ey" alt=""><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

> Every time vibration data arrives from HiveMQ Cloud → the ML server receives it, runs inference, and give the result back to Node-RED

***

### **4. Output Layer** – Returning anomaly alerts via MQTT → HiveMQ Edge → PLC (optional)

**Now we need to send the result back to HiveMQ Edge, visualize it on the dashboard or sends to the PLC for further action.**

{% stepper %}
{% step %}

#### Add MQTT out node in the flow

We will take another MQTT topic to filter and publish the result

```
hivemq-edge/machine/s71500/anomaly
```

<figure><img src="/files/OOaPUFdbwXR3t2129bIE" alt=""><figcaption></figcaption></figure>

The following flow can be used as a reference.

{% code overflow="wrap" expandable="true" %}

```json
[
    {
        "id": "1ad2c5724dad60ec",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "2e10e2177a83dbbf",
        "type": "http request",
        "z": "1ad2c5724dad60ec",
        "name": "",
        "method": "POST",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://localhost:5000/predict",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 570,
        "y": 80,
        "wires": [
            [
                "c3746a81c58e797a"
            ]
        ]
    },
    {
        "id": "1d57a237256e69e7",
        "type": "function",
        "z": "1ad2c5724dad60ec",
        "name": "function 1",
        "func": "msg.headers = { \"Content-Type\": \"application/json\" };\nmsg.payload = { value: msg.payload.value };\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 400,
        "y": 80,
        "wires": [
            [
                "2e10e2177a83dbbf"
            ]
        ]
    },
    {
        "id": "ecd705d7eabc8086",
        "type": "mqtt in",
        "z": "1ad2c5724dad60ec",
        "name": "",
        "topic": "hivemq-edge/machine/s71500/rVib",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "08f8856327f4fe37",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 160,
        "y": 80,
        "wires": [
            [
                "1d57a237256e69e7"
            ]
        ]
    },
    {
        "id": "67d96c79df053896",
        "type": "mqtt out",
        "z": "1ad2c5724dad60ec",
        "name": "",
        "topic": "hivemq-edge/machine/s71500/anomaly",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "08f8856327f4fe37",
        "x": 600,
        "y": 160,
        "wires": []
    },
    {
        "id": "c3746a81c58e797a",
        "type": "function",
        "z": "1ad2c5724dad60ec",
        "name": "function 2",
        "func": "msg.payload = msg.payload.status;\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 300,
        "y": 160,
        "wires": [
            [
                "67d96c79df053896"
            ]
        ]
    },
    {
        "id": "08f8856327f4fe37",
        "type": "mqtt-broker",
        "name": "",
        "broker": "1eba33276f3f4d2b9852f78bf6ab2880.s1.eu.hivemq.cloud",
        "port": "8883",
        "tls": "",
        "clientid": "",
        "autoConnect": true,
        "usetls": true,
        "protocolVersion": 4,
        "keepalive": 60,
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]
```

{% endcode %}
{% endstep %}

{% step %}

#### Bridge the HiveMQ Cloud MQTT topic with HiveMQ Edge MQTT topic

Go to MQTT bridge in HiveMQ Edge and add a remote subscription in your current bridge as shown below:

<figure><img src="/files/PEjrCUv9Ua55ocSswdft" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/THKGag1h29KxsJeaQa7H" alt="" width="375"><figcaption></figcaption></figure>

Now navigate to Broker Configuration and 'Enable loop prevention'. This will prevent looping of data flow

<figure><img src="/files/QR9Gffxrya8GEdhq11ct" alt="" width="375"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### Visualize Anomaly in HiveMQ Edge

Now that the anomaly arrives to MQTT Edge, you can visualize it with tools like Node-RED as shown below:

<figure><img src="/files/dRlF8zLznYXiPHae86WK" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ZJS6Oi6FSFX8XzHcoMKu" alt="" width="321"><figcaption></figcaption></figure>

{% hint style="info" %}
You can further sends the anomaly results back to PLC via OPC UA.
{% endhint %}
{% endstep %}
{% endstepper %}

***

## Complete Workflow

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FvPGMMRYPhiqsUXnsEKhl%2FHiveMQ%20Anomaly%20detection.mp4?alt=media&token=730bd29b-d752-4e25-976d-e49e406924bd>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Anomaly detection Code Explanation

Overview of the Anomaly Detection API (Flask + PyOD)

This page explains how the provided Python script works. The application uses Flask to expose an HTTP API and PyOD’s Isolation Forest model to detect anomalies in vibration data. It is designed for learners, developers, and IIoT practitioners who want to integrate machine learning into their systems (PLC, Node-RED, edge devices, etc.).

### 1. Model Training (Normal Vibration Simulation)

The script begins by simulating “normal” vibration data to train the machine learning model.

```python
normal_values = np.random.uniform(0.0, 5.0, 500)
normal_values = normal_values.reshape(-1, 1)
```

* This generates 500 vibration samples between 0 and 5 mm/s.
* These represent healthy/normal machine behaviour.

#### Scaling the Data

```python
scaler = StandardScaler()
normal_scaled = scaler.fit_transform(normal_values)
```

The data is scaled using `StandardScaler`, which helps the model handle different ranges of vibration input by normalizing values to have:

* mean = 0
* standard deviation = 1

#### Training the Isolation Forest Model

```python
model = IForest(contamination=0.05)
model.fit(normal_scaled)
```

* Isolation Forest is an unsupervised anomaly detection algorithm.
* `contamination=0.05` means we expect approximately 5% of the data to be anomalies.
* This model learns what “normal” vibration looks like.

***

### 2. Prediction API Endpoint (`/predict`)

This endpoint accepts a POST request with a vibration value and returns whether it is normal or anomalous.

Example request:

```json
{
  "value": 3.2
}
```

Processing steps:

1. Read the input vibration value.
2. Scale the value using the same scaler as the training data.
3. Run the Isolation Forest model to compute:
   * prediction (0 = normal, 1 = anomaly)
   * anomaly score

Example returned JSON:

```json
{
  "input_value": 3.2,
  "scaled_value": 0.12,
  "anomaly_score": -0.045,
  "prediction": 0,
  "status": "Normal Behaviour"
}
```

This makes it easy to connect the API to a PLC, Node-RED dashboard, or MQTT workflow.

***

### 3. Retraining Endpoint (`/retrain`)

This optional endpoint allows you to retrain the model using new samples, for example from live machine data.

Example request:

```json
{
  "samples": [0.5, 1.1, 2.0, 3.3, 1.8]
}
```

What happens internally:

1. The data is reshaped and scaled again.
2. A new Isolation Forest model is trained.
3. The global `scaler` and `model` variables are updated.

This feature is useful when:

* Machine behaviour changes over time
* You want to build a personalized model based on real data
* You need continuous improvement of detection accuracy

Response example:

```json
{
  "message": "Model retrained successfully",
  "samples_used": 5
}
```

***

#### 4. Running the Flask Server

```shellscript
app.run(host="0.0.0.0", port=5000)
```

* The server runs on port 5000.
* `0.0.0.0` makes it accessible on your local network.
* Ideal for integration with Node-RED, PLCs, or industrial dashboards.

***

### Summary

```
                ┌─────────────────────┐
                │   External Device   │
                │  (PLC / Sensor /    │
                │   Node-RED / API)   │
                └─────────┬───────────┘
                          │  POST /predict
                          │  {"value": 3.2}
                          ▼
               ┌──────────────────────────┐
               │        Flask API         │
               │    (server.py running)   │
               └──────────┬───────────────┘
                          │
                          │
          ┌───────────────┴────────────────┐
          │   Preprocessing Layer           │
          │   (StandardScaler)              │
          │                                   │
          │ - Normalizes incoming vibration   │
          │   values                          │
          │ - Ensures correct ML model input  │
          └───────────────┬──────────────────┘
                          │ scaled_value
                          ▼
               ┌──────────────────────────┐
               │  Isolation Forest Model  │
               │       (PyOD IForest)     │
               ├──────────────────────────┤
               │ Learns "normal" pattern  │
               │ Detects anomalies         │
               │ Generates anomaly score   │
               └──────────┬───────────────┘
                          │ prediction + score
                          ▼
                 ┌──────────────────┐
                 │ JSON Response    │
                 │                  │
                 │ {                │
                 │  "prediction":0  │
                 │  "status":"Normal"│
                 │  "score":-0.04   │
                 │ }                │
                 └──────────────────┘


──────────────────────────────────────────────────────────────────────
```

* Flask provides the API endpoints (`/predict` and `/retrain`).
* PyOD’s Isolation Forest detects anomalies in vibration values.
* StandardScaler normalizes the data for better model performance.
* `/predict` checks if a vibration value is normal or abnormal.
* `/retrain` lets you update the model using new machine data.
* This setup is ideal for IIoT, predictive maintenance, and real-time monitoring.


# Secure OT/IT Data Integration Using HiveMQ Edge and Site DMZ

Typical enterprise OT/IT integration using HiveMQ Edge and Site DMZ

## System Overview

In industrial environments, securely moving data from OT to IT is not about connecting everything together.&#x20;

> It’s about **placing the right components in the right network layers**.

Most enterprises deploy HiveMQ in a **layered architecture**, aligned with the automation pyramid and network zones. This article explains a typical OT/IT integration pattern using **HiveMQ Edge** and a **Site DMZ broker (Level 3.5)**.

<figure><img src="/files/N0LGNEXNDonik2YUmV3o" alt=""><figcaption></figcaption></figure>

### 1.  OT / Device Layer

At the lowest level, PLCs and field devices generate raw machine data such as:

* vibration
* temperature
* speed
* status signals

This data is typically exposed via industrial protocols such as **OPC UA**.

At this stage:

* Data stays inside the OT network
* No IT or cloud systems access PLCs directly

***

### 2.  Edge Integration Layer

**HiveMQ Edge** runs close to the machines and acts as the OT integration point.

Typical responsibilities of HiveMQ Edge include:

* Connecting to PLCs via OPC UA
* Mapping OT data to MQTT topics
* Filtering, normalizing, and buffering data
* Publishing data northbound using MQTT

Only selected and structured data leaves the OT layer.

Example topic mapping:

```
OPC UA Node   →   MQTT Topic
PLC vibration →   machine/s71500/vibration
```

***

### 3.  Site DMZ / Level 3.5

A **self-hosted HiveMQ broker** is deployed at the site level, often referred to as **Level 3.5** or the **DMZ**.

Important clarification:

* HiveMQ does not have a special “DMZ mode”
* The DMZ is enforced by **network architecture**, firewalls, and zones
* The broker simply runs **inside** that DMZ

This broker acts as:

* The aggregation point for multiple Edge instances
* The controlled handover between OT and IT

***

### 4.  IT / Enterprise Layer

From the Site DMZ broker, data can be consumed by:

* analytics platforms
* dashboards
* AI / ML systems
* ERP or MES applications
* cloud services

IT systems subscribe to MQTT topics exposed by the DMZ broker — **not** to PLCs or Edge devices.

***

### Key Security Principle

> **OT never connects directly to IT.**\
> The Site DMZ broker is the single, controlled handover point.

This approach:

✅ Preserves OT isolation\
✅ Scales across sites and factories\
✅ Aligns with UNS and enterprise security practices

***

## Summary

HiveMQ Edge and a Site DMZ broker form a clean and secure OT/IT integration pattern:

* Edge handles OT complexity
* The DMZ broker enforces architectural separation
* IT systems consume data without exposing the OT network

This layered approach mirrors how most enterprises deploy HiveMQ within their UNS and IIoT strategies.

***

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# ThingsBoard

ThingsBoard is an open-source IoT Platform that allows Device management, data collection, processing, and visualization for your IoT solution.

<figure><img src="/files/KR6R4l0u2ZUZ5V1z2x4Q" alt=""><figcaption></figcaption></figure>

You will find several guides here on using ThingsBoard for IoT applications. You can use these guides to:

* Set up and install ThingsBoard on the edge device
* Send telemetry data from the Factory to the ThingsBoard dashboard
* Send Factory data to the ThingsBoard Cloud

#### What you’ll find in the sub-pages

* [ThingsBoard (Edge Setup)](/product-reviews/smart-platforms/thingsboard/thingsboard-edge-setup)\
  This guide shows how to build a complete end-to-end IIoT system using ThingsBoard running on an edge device and simulated telemetry data.
* [Real-Time Vibration Monitoring with ThingsBoard and Calculated Fields](/product-reviews/smart-platforms/thingsboard/real-time-vibration-monitoring-with-thingsboard-and-calculated-fields)\
  This guide shows how to build a complete end-to-end industrial vibration monitoring system from a real Balluff condition monitoring sensor, through a virtual PLC, to a live ThingsBoard dashboard with ISO 10816-compliant alarms.

{% hint style="info" %}
Each article is intentionally architecture-focused and vendor-neutral, reflecting how ThingsBoard is deployed in real industrial environments.
{% endhint %}

{% hint style="success" %}

#### Want to get started with ThingsBoard? Sign up [here](https://thingsboard.io/?fpr=n5sson\&fp_sid=rajvir).

{% endhint %}


# ThingsBoard (Edge Setup)

This guide shows how to build a complete end-to-end IIoT system using ThingsBoard running on an edge device and simulated telemetry data.

Unlike fragmented solutions that require multiple tools glued together, **ThingsBoard provides the full system operators actually use, from device connectivity to role-based dashboards, out of the box**.

**By the end of this guide, you will have:**

* ThingsBoard running on a **reComputer R2100**
* A device connected via **MQTT**
* Simulated telemetry generated from **Node-RED.** In our guide, we will be using **Node-RED** to emulate device data for this setup. Learn more about Node-RED [here](https://nodered.org/)
* A **live industrial dashboard** (motor, energy, vibration, etc.)
* Optional **RPC control** from the dashboard to the device

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FXX5i4KqlYXHfbyxxxpFY%2FThingsBoard.mp4?alt=media&token=1c3cdfb8-77e4-4c75-b7e5-b87374b7266e>" %}

{% hint style="success" %}

#### Want to get started with ThingsBoard? Sign up [here](https://thingsboard.io/?fpr=n5sson\&fp_sid=rajvir).

{% endhint %}

### Hardware & Software Used

#### Hardware

* **reComputer R2100** (Edge device) from Seeed Studio
* Development PC / Laptop

#### Software

* ThingsBoard Community Edition (CE)
* Node-RED (for sending simulated telemetry data)
* MQTT Broker (built into ThingsBoard)

***

### Step 1 – Install ThingsBoard on the reComputer R2100

{% hint style="info" %}
You can use any Linux-based edge device with at least 4GB of RAM. Get more information [here](https://thingsboard.io/docs/user-guide/install/rpi/?utm_source=inf\&utm_medium=rjvr\&utm_campaign=edgesetup)
{% endhint %}

{% stepper %}
{% step %}

### Log in to reComputer via Putty

<figure><img src="/files/ErDsoMdsI3azEDWsdNfG" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Install ThingsBoard

You can follow the instructions given on thingsBoard documentation here: <https://thingsboard.io/docs/user-guide/install/rpi/?utm_source=inf&utm_medium=rjvr&utm_campaign=edgesetup>

Once you have finished installing ThingsBoard, come back here.
{% endstep %}
{% endstepper %}

### Step 2- Start ThingsBoard and open the WebUI

{% stepper %}
{% step %}

### Start ThingsBoard on your edge device

```shellscript
sudo service thingsboard start
```

{% endstep %}

{% step %}

### Open WebUI

Open this on your browser: [http://192.168.0.195:8080](http://192.168.0.195:8080/login) where 192.168.0.195 is the IP address of the edge device.
{% endstep %}

{% step %}

### Log in as Admin

Log in using the following credentials:

* **Username**: <sysadmin@thingsboard.org>&#x20;
* **Password**: sysadmin

<figure><img src="/files/pN6OSfY7mLkEqR8scI43" alt="" width="278"><figcaption></figcaption></figure>

<figure><img src="/files/4jkh21t3xWp1QEsjgv18" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Create a new Tenant

**Multitenancy in ThingsBoard** enables you to manage multiple organizations within a single system. Each tenant works like an independent environment with its own users, devices, and dashboards.

<figure><img src="/files/ghoTaxqvzvRzOin0JnFz" alt=""><figcaption></figcaption></figure>

The steps to create the tenant are given here: <https://thingsboard.io/docs/user-guide/ui/tenants/?utm_source=inf&utm_medium=rjvr&utm_campaign=edgesetup>
{% endstep %}

{% step %}

### Add the user in the Tenant as 'Admin'

The **System administrator** can also create multiple users with the Tenant Administrator **role** in each tenant.

<figure><img src="/files/uUufo1uXQTyfQhVxntND" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Log in as 'Tenant user.'

<figure><img src="/files/iSIaVvke9pcmbSQW4F0C" alt=""><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

### Step 3- Add a new device and send a test value

Let's add a device that sends telemetry data to ThingsBoard.&#x20;

{% stepper %}
{% step %}

### Add a device

The detailed steps of instructions on adding a device are given here: <https://thingsboard.io/docs/getting-started-guides/helloworld/?utm_source=inf&utm_medium=rjvr&utm_campaign=edgesetup>

<figure><img src="/files/X26XZGaw3KsD7FhlqXhL" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Select the communication protocol

There are multiple ways to connect to the ThingsBoard device. In our example, we will use MQTT.&#x20;

<figure><img src="/files/cF7ONJKk73UDbBjHlXoc" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Get ThingsBoard MQTT connection details

The ThingsBoard has an internal MQTT Broker running on port 1883. You will find more details for the connection in the wizard.

```shellscript
mosquitto_pub -d -q 1 -h 192.168.0.195 -p 1883 -t v1/devices/me/telemetry -u "IPOJzEMJHs0wWhzz2K3R" -m "{temperature:25}"
```

In the above lines of code, we can extract the following information needed to send telemetry data to ThingsBoard via MQTT:

* Broker URL: 192.168.0.195 (IP Address of the edge device)
* MQTT Port: 1883
* MQTT Topic: v1/devices/me/telemetry
* Username: IPOJzEMJHs0wWhzz2K3R
* Password: — leave blank --
  {% endstep %}

{% step %}

### Send a test value to ThingsBoard via MQTT

Take the inject node as 'Timestamp' with an interval of 1 second.

<figure><img src="/files/XWb8YXLQofKXQLkYELcQ" alt=""><figcaption></figcaption></figure>

Add a function node to simulate temperature value

```javascript
let number = Number((Math.random() * 100).toFixed(2));
msg.payload = {
    temperature: number
}
return msg;
```

Take the MQTT out node and set up the ThingsBoard's MQTT broker parameters as shown in the image:

<figure><img src="/files/opTx7FqIz0TcQzAi5fiJ" alt=""><figcaption></figcaption></figure>

Enter the username:

<figure><img src="/files/VcHl15w73fFwPKPIKz1b" alt=""><figcaption></figcaption></figure>

Define the MQTT topic:

<figure><img src="/files/EwFJbKUXk22gLC3skhZX" alt=""><figcaption></figcaption></figure>

Once the connection is established, send a test value as 'temperature':

<figure><img src="/files/f9wjhG4ag0H1U8qkbxFW" alt=""><figcaption></figcaption></figure>

Open the telemetry log to view the temperature value. Navigate to **Entities > Devices > IoT1 > Latest Telemetry**

<figure><img src="/files/KSqwUmOekNrePPMO9FwA" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

### Step 4- Update telemetry data in the Node-RED

To visualize multiple parameters on the ThingsBoard dashboard, we need additional telemetry data. Use the following code in the function node of Node-RED.

```javascript
// Rich telemetry generator for ThingBoard dashboards
// Put this in a Function node and trigger it every 1s-5s with an Inject node.

let s = context.get('s') || {
    t: 0,
    baseTemp: 24,
    baseHum: 48,
    motorOn: true,
    speedRpm: 900,
    energyKWh: 0,
    runtimeSec: 0,
    cycleCount: 0,
    lastCycleT: 0,
    fault: false,
    faultCode: 0
};

s.t += 1;

// Helpers
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }
function rand(min, max) { return min + Math.random() * (max - min); }
function chance(p) { return Math.random() < p; }

// ---- Motor state machine (feels realistic)
if (chance(0.02)) s.motorOn = !s.motorOn;              // occasional start/stop
if (chance(0.01) && !s.fault) {                        // rare fault event
    s.fault = true;
    s.faultCode = [101, 202, 303, 404][Math.floor(Math.random() * 4)];
}
if (s.fault && chance(0.15)) {                         // fault clears after some time
    s.fault = false;
    s.faultCode = 0;
}

// Speed ramping
let targetRpm = s.motorOn && !s.fault ? rand(800, 1450) : 0;
s.speedRpm = s.speedRpm + (targetRpm - s.speedRpm) * 0.15;
s.speedRpm = clamp(s.speedRpm, 0, 1600);

// ---- Environmental signals (slow drift + small noise)
let dayWave = Math.sin(s.t / 120) * 1.5;               // slow wave
s.baseTemp += rand(-0.02, 0.02);
s.baseHum += rand(-0.05, 0.05);

let temperature = clamp(s.baseTemp + dayWave + rand(-0.2, 0.2), 18, 35);
let humidity    = clamp(s.baseHum - dayWave + rand(-0.5, 0.5), 30, 70);

// ---- Vibration rises with RPM + faults
let vibBase = (s.speedRpm / 1600) * 4.0;               // 0..4 mm/s
let vibrationRms = vibBase + rand(0.1, 0.5);
if (s.fault) vibrationRms += rand(2, 5);               // big increase when faulty
vibrationRms = clamp(vibrationRms, 0, 12);

// ---- Current / Power / Energy
let currentA = s.motorOn && !s.fault ? clamp((s.speedRpm / 1600) * 7 + rand(0, 1), 0, 10) : rand(0, 0.3);
if (s.fault) currentA += rand(2, 4);

let voltageV = 230 + rand(-3, 3);
let powerW = clamp(voltageV * currentA * 0.85, 0, 4000);   // rough PF/efficiency

// energy integration: Wh per second -> kWh
s.energyKWh += (powerW / 1000) / 3600;

// ---- Production-ish signals
if (s.motorOn && !s.fault) s.runtimeSec += 1;

// create a "cycle" every ~15-35 seconds when running
if (s.motorOn && !s.fault && (s.t - s.lastCycleT) > rand(15, 35)) {
    s.cycleCount += 1;
    s.lastCycleT = s.t;
}
let cycleTimeSec = s.motorOn && !s.fault ? clamp((s.t - s.lastCycleT), 0, 60) : null;

// ---- Quality / OEE-ish
let rejectRate = s.fault ? rand(3, 12) : rand(0.3, 2.0);   // %
let goodParts = Math.round(s.cycleCount * (1 - rejectRate / 100));
let availability = clamp((s.runtimeSec / s.t) * 100, 0, 100);

// ---- Alarm levels (nice for color-changing widgets)
let alarmLevel = 0;
if (temperature > 30 || vibrationRms > 7) alarmLevel = 1;
if (s.fault || vibrationRms > 9) alarmLevel = 2;

// Build payload
msg.payload = {
    // Environment
    temperature: Number(temperature.toFixed(2)),          // °C
    humidity: Number(humidity.toFixed(2)),                // %

    // Machine
    motorOn: s.motorOn && !s.fault,                       // boolean
    speedRpm: Math.round(s.speedRpm),
    vibrationRms: Number(vibrationRms.toFixed(2)),        // mm/s
    currentA: Number(currentA.toFixed(2)),                // A
    voltageV: Number(voltageV.toFixed(1)),                // V
    powerW: Math.round(powerW),                           // W
    energyKWh: Number(s.energyKWh.toFixed(3)),            // kWh

    // Production / KPIs
    cycleCount: s.cycleCount,
    cycleTimeSec: cycleTimeSec === null ? null : Number(cycleTimeSec.toFixed(1)),
    goodParts: goodParts,
    rejectRate: Number(rejectRate.toFixed(2)),            // %
    availability: Number(availability.toFixed(1)),        // %

    // Faults / Alarms
    fault: s.fault,
    faultCode: s.faultCode,
    alarmLevel: alarmLevel                               // 0 normal, 1 warn, 2 critical
};

context.set('s', s);
return msg;

```

This updated code will give you multiple simulated values as shown below:

<figure><img src="/files/RLlc6owy0wWVyqos3bf6" alt="" width="563"><figcaption></figcaption></figure>

### Step 5- Create Dashboard

We will now create a dashboard to visualize telemetry data. The step-by-step information on creating the dashboard is given here: <https://thingsboard.io/docs/user-guide/dashboards/?utm_source=inf&utm_medium=rjvr&utm_campaign=edgesetup>

<figure><img src="/files/kANUevednq5dGNY8SDcS" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="/files/jAqcghqxAfiBEWazc5rI" alt="" width="563"><figcaption></figcaption></figure>

{% stepper %}
{% step %}

### Add new widget

Open your dashboard and click on 'Add new widget'

<figure><img src="/files/swTZNuFA9MTEai47jL3I" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Select 'Cards' in the widget bundle

<figure><img src="/files/QwlxvaD8I03ycs0k4DRW" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Select Label & value card

<figure><img src="/files/28khgdUZmWxaCvPHTuCS" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Configure the parameters

* Locate your IoT device. In our case, it is 'IoT1.'
* Update the label to 'Temperature.'
* Update the icon and color as required.
* Click on 'Add'

<figure><img src="/files/LJAQBs03RdZtPRfhuKBK" alt="" width="563"><figcaption></figcaption></figure>

{% hint style="info" %}
💡 **Best practice (recommended for shared dashboards)**

In production or reusable dashboards, avoid selecting a fixed **Device**.\
Instead, use an **Entity Alias** resolved from the dashboard state.

This allows the same dashboard to work across different devices and instances.
{% endhint %}
{% endstep %}

{% step %}

### Visualize the Dashboard

You will instantly see the Temperature value on the dashboard

<figure><img src="/files/pZ2CzPdymE7d74sEX8un" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

## Step 6- Import dashboard

ThingsBoard makes it really easy to share a dashboard. Follow these steps to duplicate my ThingsBoard dashboard.

{% stepper %}
{% step %}

### Click on Add Dashboard > Import

<figure><img src="/files/nIhJ7JRCegNJYhOMS7e1" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Download my dashboard

Click on the file below to keep a copy of the dashboard

{% file src="/files/nqMuNfU6DtPOIa9kMGS4" %}
{% endstep %}

{% step %}

### 🔁 About Entity Alias & Reusability (Important)

This dashboard is exported using **an entity alias** instead of a fixed device.

What this means:

* The dashboard is **not hard-coded** to a specific device
* It can be reused across **different ThingsBoard instances**
* All widgets dynamically resolve the device from the **dashboard state**

During import, ThingsBoard will automatically use the **default state entity** defined in the dashboard.\
You can change this at any time to point the dashboard to **your own device**.

***

### Importing Dashboard

Drag and drop the file into the wizard, then click 'Import.' You will find the imported dashboard in the list.&#x20;

***

#### After importing the dashboard

If your device name is different from `IoT1`, follow these steps:

1. Open the imported dashboard
2. Click **Edit → Aliases**
3. Select the alias (for example: `IoT1`)
4. Choose your own **Device**
5. Save the dashboard

All widgets will update automatically. Click it to view all sample telemetry data on your screen.

<figure><img src="/files/daerBfYHFK2P5JerfGzt" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="/files/jsmW6RNeiIa2H3OA2aDj" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="/files/bDIajE3MJ7H8GBDKhsWc" alt="" width="563"><figcaption></figcaption></figure>

Enjoy exploring the dashboard elements.&#x20;

***

#### Why Entity Alias is recommended

Using Entity Alias instead of selecting a device directly:

* Makes dashboards **portable and shareable**
* Prevents broken widgets after import
* Allows the same dashboard to work with **multiple devices**
* Follows **ThingsBoard's best practices** for production dashboards
  {% endstep %}
  {% endstepper %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Real-Time Vibration Monitoring with ThingsBoard and Calculated Fields

This guide shows how to build a complete end-to-end industrial vibration monitoring system from a real Balluff condition monitoring sensor, through a virtual PLC, to a live ThingsBoard dashboard with ISO 10816-compliant alarms.

Unlike the [previous article](https://wiki.codeandcompile.com/product-reviews/smart-platforms/thingsboard/thingsboard-edge-setup), which used simulated telemetry from Node-RED, **this guide uses real vibration data from a physical sensor** connected via IO-Link and streamed live to [ThingsBoard](https://thingsboard.io/?utm_source=inf\&utm_medium=rjvr\&utm_campaign=artcl2) using OPC UA and MQTT.

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FNzPNDdsCpAdzyeZhuBgj%2FThingsBoard.mp4?alt=media&token=201aa1e1-d9c1-4626-96f6-2e09e8e71c7e>" %}

**By the end of this guide, you will have:**

* Real X/Y/Z vibration RMS data streaming from a Balluff condition monitoring sensor
* A **reComputer vPLC** reading sensor data via Modbus TCP/IP over IO-Link
* A **reComputer R1100** bridging data from the vPLC (OPC UA) to ThingsBoard's MQTT Broker using Node-RED
* [**ThingsBoard Calculated Fields**](https://thingsboard.io/docs/pe/user-guide/calculated-fields/?utm_source=inf\&utm_medium=rjvr\&utm_campaign=artcl2) compute ISO 10816 vibration severity and machine health status in real time
* A professional dashboard with a color-coded gauge, alarms, and a dynamic machine health card

{% hint style="success" %}

#### Want to get started with ThingsBoard? Sign up [here](https://thingsboard.io/?fpr=n5sson\&fp_sid=rajvir).

{% endhint %}

***

## Hardware & Software Used

### Hardware

| Component                         | Model                                    |
| --------------------------------- | ---------------------------------------- |
| Edge Computer (vPLC host)         | Seeed reComputer R2100 (OpenPLC Runtime) |
| Edge Gateway and ThingsBoard Host | Seeed reComputer R1100                   |
| IO-Link Master                    | Balluff BNI00L3                          |
| Condition Monitoring Sensor       | Balluff BCM R15E-001-DI00-01,5-S4        |

### Software

* OpenPLC vPLC Runtime (on reComputer R2100)
* Node-RED (on reComputer R1100)
* ThingsBoard Community Edition (on reComputer R1100)

***

## System Architecture

Before diving into the steps, it's helpful to understand how data flows through the system.

```
[Balluff BCM Sensor]
        │
        │  IO-Link
        ▼
[Balluff IO-Link Master — BNI00L3]
        │
        │  Modbus TCP/IP
        ▼
[reComputer R2100 — OpenPLC vPLC]
   - Reads X/Y/Z VRMS + Temperature
   - Byte-swaps Big-Endian floats
   - Exposes values via OPC UA Server
        │
        │  OPC UA
        ▼
[reComputer R1100 — Node-RED]
   - OPC UA Client reads live values
   - Publishes JSON payload via MQTT
        │
        │  MQTT (port 1883)
        ▼
[reComputer R1100 — ThingsBoard]
   - Receives telemetry
   - Runs Calculated Fields (Vibration Severity, Machine Status)
   - Triggers ISO 10816 alarms
   - Displays live dashboard
```

{% hint style="info" %}
💡 **Why two edge devices?** The vPLC (reComputer R2100 running OpenPLC) is dedicated to real-time scan-cycle control and sensor I/O. A separate computer, R1100, handles the edge communication. This separation keeps the PLC runtime clean and follows industrial best practices for separating control logic from data forwarding.
{% endhint %}

***

### Step 1: Hardware Setup (vPLC + IO-Link)

This step is covered in detail in the [Virtual PLC interfacing with IO-Link Master](https://wiki.codeandcompile.com/product-reviews/smart-platforms/virtual-plcs/autonomy-edge-openplc-redefined/virtual-plc-interfacing-with-io-link-master) article.

In summary, the vPLC:

1. Connects to the **Balluff IO-Link Master** over Modbus TCP/IP
2. Reads X/Y/Z VRMS and Temperature from registers `IW1`–`IW8`
3. Uses a **custom C++ WTOR function block** to byte-swap Big-Endian 32-bit floats into usable `REAL` values
4. Stores the results in `rX_VRMS`, `rY_VRMS`, `rZ_VRMS`, and `rTemp`

{% hint style="info" %}
**Key point:** The Balluff sensor sends each float split across 2 × 16-bit Modbus registers in Big-Endian format. A direct cast to `REAL` gives garbage values — the byte swap is mandatory. The WTOR function block handles this automatically.
{% endhint %}

Once the vPLC is running and reading correct values, proceed to Step 2.

***

### Step 2: Expose vPLC Data via OPC UA

The vPLC exposes its runtime variables as an OPC UA Server. This allows the reComputer R1100 to read live values without changing the PLC program.

{% hint style="info" %}
OpenPLC Runtime includes a built-in OPC UA server. No additional configuration is required; variables declared in the PLC program are automatically available as OPC UA nodes.
{% endhint %}

Note the OPC UA server address of the vPLC; you will need this in the next step:

```
opc.tcp://192.168.100.10:4840
```

Replace `192.168.100.10` with the actual IP address of your vPLC.

***

### Step 3: Bridge OPC UA to MQTT using Node-RED&#x20;

The reComputer R1100 runs **Node-RED** as the middleware layer. It acts as an OPC UA client that reads vibration values from the vPLC and publishes them to ThingsBoard's MQTT broker every second.

{% stepper %}
{% step %}

### Install the OPC UA node in Node-RED

Open the Node-RED palette manager and install:

```
node-red-contrib-opcua
```

{% endstep %}

{% step %}

### Build the flow

<figure><img src="/files/AFBLvzejZSUnnsWhRXam" alt="" width="563"><figcaption></figcaption></figure>

The flow consists of three parts:

<details>

<summary><strong>Trigger (every 1 second)</strong></summary>

Use an **Inject** node set to repeat every 1 second.

</details>

<details>

<summary><strong>OPC UA Read</strong></summary>

Add an **OPC UA Client** node and configure it:

* Endpoint: `opc.tcp://192.168.100.10:4840`
* Action: `READ`
* Node IDs to read:
  * `ns=4;i=1`
  * `ns=4;i=2`
  * `ns=4;i=3`
  * `ns=4;i=4`
  * `ns=4;i=5`
  * `ns=4;i=6`
  * `ns=4;i=7`

{% hint style="info" %}
The exact node ID format depends on your OpenPLC version. Use the OPC UA browser (built into the OpcUa-Client node) to confirm the correct node paths for your setup.
{% endhint %}

</details>
{% endstep %}

{% step %}

### Create a Device Profile in ThingsBoard

{% hint style="info" %}
Device profiles in ThingsBoard enable administrators to define and centrally manage common settings for multiple devices. This greatly simplifies the management of a large number of similar devices, making it especially valuable in IoT solutions where numerous devices share identical configurations and behaviors.

Learn more about the device profile [here](https://thingsboard.io/docs/user-guide/device-profiles/)
{% endhint %}

Go to **Profiles → Device Profiles** in the left menu → click **+** → Create new device profile

<figure><img src="/files/CUAGwyF70nFnC2UmGKzp" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Create a new device

Create a new device and link that to the device profile created above. In our case, the new device is named '**OpenPLC**', linked to the device profile '**Vibration Sensor'**.&#x20;

<figure><img src="/files/UpOJ2LbdfZYpyYszrXr6" alt="" width="563"><figcaption></figcaption></figure>

### How to Link your device to the "Vibration Sensor" device Profile

**Step 1:** Go to **Entities → Devices**&#x20;

**Step 2:** Click on **OpenPLC (your device)** to open its details

**Step 3:** Click the **pencil/edit icon** (✏️) in the top right of the details panel

**Step 4:** Find the **"Device profile"** field — currently shows `default`

**Step 5:** Click on it and select **"Vibration Sensor"** from the dropdown

<figure><img src="/files/A8bq1J0IYFriVfzNR6Wr" alt="" width="563"><figcaption></figcaption></figure>

**Step 6:** Click **Save / Apply changes**

<figure><img src="/files/bIGIDcJUnPGS6oU2RpWG" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Format and publish the PLC data to the MQTT Broker

Add a **Function** node in the Node-RED to format the payload:

```javascript
// Build payload
msg.payload = {
    // OpenPLC
    plc_rThresholdHigh: msg.payload["ns=2;i=6"].toFixed(3),
    plc_rThresholdLow: msg.payload["ns=2;i=5"].toFixed(3),
    plc_rSensortemp: msg.payload["ns=2;i=7"].toFixed(3),
    plc_iVibrationState: msg.payload["ns=2;i=4"],
    plc_rSensorX_vrms: msg.payload["ns=2;i=1"].toFixed(3),
    plc_rSensorY_vrms: msg.payload["ns=2;i=2"].toFixed(3),
    plc_rSensorZ_vrms: msg.payload["ns=2;i=3"].toFixed(3),
};
return msg;
```

Add an **MQTT Out** node with the ThingsBoard connection details as shown below.

| Setting       | Value                                                                                                                                                                                                                             |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Broker        | <p><code>192.168.0.227</code> <br>(IP of reComputer R1100)</p>                                                                                                                                                                    |
| Port          | `1883`                                                                                                                                                                                                                            |
| Topic         | `v1/devices/me/telemetry`                                                                                                                                                                                                         |
| Username      | Your ThingsBoard device username. Check [this](https://wiki.codeandcompile.com/product-reviews/smart-platforms/thingsboard/thingsboard-edge-setup#get-thingsboard-mqtt-connection-details) step to learn how to get the username. |
| Password      | *(leave blank)*                                                                                                                                                                                                                   |
| {% endstep %} |                                                                                                                                                                                                                                   |

{% step %}

### Verify data is arriving in ThingsBoard

Go to your ThingsBoard device → **Latest Telemetry** tab. You should see the four keys updating every second:

<figure><img src="/files/LOolIVbM5X5gddVLJQu4" alt="" width="455"><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

***

### Step 4: Create Calculated Fields in ThingsBoard

This is where the raw sensor data becomes actionable. ThingsBoard v4.0 introduced **Calculated Fields**, a built-in logic layer that transforms incoming telemetry in real time without any external scripts or rule chains.

We will create two calculated fields:

1. **Overall Vibration Severity:** combines X/Y/Z into a single ISO 10816 metric
2. **Machine Status:** classifies the severity into a human-readable health state

{% hint style="info" %}
Best Practice Note: Instead of attaching a calculated field to a specific device (e.g., IoT1), it is recommended to attach it to a Device Profile. This way, the calculated field automatically applies to all devices sharing that profile, making your setup scalable and maintainable without duplicating configuration.
{% endhint %}

***

{% stepper %}
{% step %}

### Create the calculated fields

Go to **Profiles → Device Profiles** **→ Open your device profile ('Vibration Sensor')**

Navigate to the **Calculated Fields** tab inside the profile. Click **+** and create a calculated field

<figure><img src="/files/el3weWuBnTyVWfOVv4V4" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Calculated Field 1: Overall Vibration Severity (ISO 10816)

Navigate to your Left tree menu→ **Calculated Fields** tab → click **+**.

**General settings:**

| Setting | Value                                            |
| ------- | ------------------------------------------------ |
| Title   | Overall Vibration Severity (ISO 10816 compliant) |
| Type    | Script                                           |

Add three arguments:

| Argument name       | Type             | Key                 |
| ------------------- | ---------------- | ------------------- |
| plc\_rSensorX\_vrms | Latest telemetry | `plc_rSensorX_vrms` |
| plc\_rSensorY\_vrms | Latest telemetry | `plc_rSensorY_vrms` |
| plc\_rSensorZ\_vrms | Latest telemetry | `plc_rSensorZ_vrms` |

<figure><img src="/files/Y2nxgoZoRquHV3eznUTp" alt=""><figcaption></figcaption></figure>

**Add this Script:**

```javascript
var vibration_severity = Math.sqrt(plc_rSensorX_vrms * 
    plc_rSensorX_vrms + plc_rSensorY_vrms * plc_rSensorY_vrms + 
    plc_rSensorZ_vrms * plc_rSensorZ_vrms);
return {
    "vibration_severity":  toFixed(vibration_severity,3)
}
```

**Output: Time series**

{% hint style="info" %}
**Why vector magnitude?** Using `sqrt(X² + Y² + Z²)` rather than the maximum individual axis, it gives you the true Euclidean magnitude of the vibration vector. This is the correct approach for ISO 10816 compliance and eliminates false negatives,  a situation where all three axes are below threshold individually, but combined vibration is dangerously high.
{% endhint %}
{% endstep %}

{% step %}

### Calculated Field 2: Machine Status

Navigate to **Calculated Fields** → click **+** again.

**General settings:**

| Setting | Value          |
| ------- | -------------- |
| Title   | Machine Status |
| Type    | Script         |

**Arguments:**

<table><thead><tr><th width="189.6666259765625">Argument name</th><th>Type</th><th width="191.6666259765625">Key</th><th>Default value</th></tr></thead><tbody><tr><td>vibration_severity</td><td>Latest telemetry</td><td><code>vibration_severity</code></td><td><code>0</code></td></tr></tbody></table>

<figure><img src="/files/EypIGN2jI6zjvFaYPxY6" alt=""><figcaption></figcaption></figure>

> ⚠️ Setting a default value of `0` is important. Without it, if `vibration_severity` has not yet been computed, the argument receives `null`, the comparison fails, and the status incorrectly shows `CRITICAL`.

**Add this Script:**

```javascript
if (vibration_severity < 2.3) {
        return { "machine_status": "HEALTHY" };
    } else if (vibration_severity < 4.5) {
        return { "machine_status": "WARNING" };
    } else if (vibration_severity < 7.1) {
        return { "machine_status": "CRITICAL" };
    } else {
        return { "machine_status": "EMERGENCY" };
    }
```

<figure><img src="/files/ob5Kp9hcwFDrjaVSe9Ul" alt=""><figcaption></figcaption></figure>

**ISO 10816-3 zone reference:**

<table><thead><tr><th width="90.33331298828125">Zone</th><th width="155.3333740234375">Severity range</th><th width="142.6666259765625">Status</th><th>Meaning</th></tr></thead><tbody><tr><td>A</td><td>0 – 2.3 mm/s</td><td>HEALTHY</td><td>Good - new or recently serviced</td></tr><tr><td>B</td><td>2.3 – 4.5 mm/s</td><td>WARNING</td><td>Acceptable - monitor closely</td></tr><tr><td>C</td><td>4.5 – 7.1 mm/s</td><td>CRITICAL</td><td>Unsatisfactory - schedule maintenance</td></tr><tr><td>D</td><td>> 7.1 mm/s</td><td>EMERGENCY</td><td>Unacceptable - risk of damage</td></tr></tbody></table>
{% endstep %}
{% endstepper %}

***

### Step 5: Configure Alarms

Navigate to your **Device Profile** → **Alarm Rules** tab.

Create three alarm rules based on `vibration_severity`:

<figure><img src="/files/h8XCWaHEMtV23HUdFcVP" alt="" width="563"><figcaption></figcaption></figure>

***

#### Alarm 1: Motor Vibration Warning

| Setting   | Value                               |
| --------- | ----------------------------------- |
| Condition | `return (vibration_severity > 2.3)` |

<figure><img src="/files/YUUBXRZ8nvFRsoJAvyd0" alt="" width="563"><figcaption></figcaption></figure>

**Additional info:**

{% hint style="warning" %}
\[WARNING] Motor Vibration entering Zone B (ISO 10816) Severity: ${vibration\_severity} mm/s | Threshold: 2.3 mm/s Axis breakdown — X: ${plc\_rSensorX\_vrms} mm/s | Y: ${plc\_rSensorY\_vrms} mm/s | Z: ${plc\_rSensorZ\_vrms} mm/s Action: Monitor closely. Schedule inspection if sustained.
{% endhint %}

***

#### Alarm 2: Motor Vibration Critical

| Setting   | Value                               |
| --------- | ----------------------------------- |
| Condition | `return (vibration_severity > 4.5)` |

<figure><img src="/files/WGpS3Yw9NFmcqoyL9Jmc" alt="" width="563"><figcaption></figcaption></figure>

**Additional info:**

{% hint style="danger" %}
\[CRITICAL] Motor Vibration in Zone C — Maintenance Required (ISO 10816) Severity: ${vibration\_severity} mm/s | Threshold: 4.5 mm/s Axis breakdown — X: ${plc\_rSensorX\_vrms} mm/s | Y: ${plc\_rSensorY\_vrms} mm/s | Z: ${plc\_rSensorZ\_vrms} mm/s Action: Reduce load and schedule immediate inspection.
{% endhint %}

***

#### Alarm 3: Motor Vibration Emergency

| Setting   | Value                              |
| --------- | ---------------------------------- |
| Condition | `return (vibration_severity > 7.1` |

<figure><img src="/files/FKz1EslrHIV6ANJTXoWn" alt="" width="563"><figcaption></figcaption></figure>

**Additional info:**

{% hint style="danger" %}
\[EMERGENCY] Motor Vibration in Zone D — Shutdown Risk (ISO 10816) Severity: ${vibration\_severity\_r} mm/s | Threshold: 7.1 mm/s Axis breakdown — X: ${plc\_rSensorX\_vrms\_r} mm/s | Y: ${plc\_rSensorY\_vrms\_r} mm/s | Z: ${plc\_rSensorZ\_vrms\_r} mm/s Action: Stop machine immediately. Risk of mechanical damage.
{% endhint %}

{% hint style="success" %}
**Why use `vibration_severity` for alarms instead of individual axes?**&#x20;

Alarming on individual X/Y/Z values creates two problems: false negatives (all axes below threshold but combined severity is dangerous) and false positives (one axis spikes from a single knock while overall severity stays in Zone A). The combined severity metric is ISO-compliant and gives a much cleaner alarm signal.
{% endhint %}

***

### Step 6: Build the Dashboard

{% stepper %}
{% step %}

### Machine Health card (HTML Value Card)

<figure><img src="/files/SkAwvYr2rytemMU078QX" alt=""><figcaption></figcaption></figure>

Add widget → **Cards** → **HTML Value Card**

Type: Entity

Data key: `machine_status`

Navigate to 'Appearance'. Paste the following into the HTML section:

```html
<!DOCTYPE html>
<html>
<head></head>
<body style="margin:0; padding:0;">
<div class="card" id="statusCard">
  <div class="content">
    <div style="text-align:center; width:100%;">
      <div style="font-size:13px; color:white; opacity:0.8;">Machine Health</div>
      <div style="font-size:28px; font-weight:bold; color:white;">${machine_status}</div>
    </div>
  </div>
</div>

<script>
  var status = '${machine_status}';
  var card = document.getElementById('statusCard');
  if (status === 'HEALTHY') {
    card.style.backgroundColor = '#4CAF50';
  } else if (status === 'WARNING') {
    card.style.backgroundColor = '#FFEB3B';
  } else if (status === 'CRITICAL') {
    card.style.backgroundColor = '#FF9800';
  } else {
    card.style.backgroundColor = '#F44336';
  }
</script>
</body>
</html>
```

Replace the CSS section with:

```css
.card {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    border: none;
}

.card .content {
    padding: 20px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    height: 100%;
}
```

{% endstep %}

{% step %}

### Widget 1: Warning Card

<figure><img src="/files/5VNbSkLKsVVzjuVg9ZPZ" alt="" width="220"><figcaption></figcaption></figure>

1. Click **+ Add widget** → **Cards** → **Alarm count**
2. Configure:

| Setting               | Value                           |
| --------------------- | ------------------------------- |
| Label                 | Warnings                        |
| Alarm severity filter | Warning                         |
| Alarm status filter   | Active                          |
| Icon                  | Warning triangle, Size 20px     |
| Icon color            | White                           |
| Icon background       | `#2E7D6B` (dark teal, as shown) |
| {% endstep %}         |                                 |

{% step %}

### Widget 2: Critical Alarms Card

Same steps as above but:

| Setting               | Value                |
| --------------------- | -------------------- |
| Label                 | Critical Alarms      |
| Alarm severity filter | Critical             |
| Icon background       | `#C62828` (dark red) |
| {% endstep %}         |                      |

{% step %}

### Widget 3: Motor Image

* Click **+ Add widget** → **Traditional SCADA Fluid system**→ **Right motor pump**

| Setting        | Value                                                                      |
| -------------- | -------------------------------------------------------------------------- |
| Running        | `True`                                                                     |
| Warning State  | <p>Use alarm status: Warning<br>Alarm Type: Motor Vibration</p>            |
| Critical State | <p>Use alarm status: Critical and Major<br>Alarm Type: Motor Vibration</p> |
| {% endstep %}  |                                                                            |

{% step %}

### Vibration Severity Gauge (ISO 10816 bands)

<figure><img src="/files/JMZPSh2pLtJIDjkVxxHU" alt="" width="355"><figcaption></figcaption></figure>

Add widget → **Gauges** → **Speed Gauge**

Type: Entity

Antity Alias: OpenPLC

Data key: `vibration_severity`

Configure the colour bands to match ISO 10816 zones in the Scale settings:

<figure><img src="/files/1WeXG3it7enKEmk6hutt" alt="" width="563"><figcaption></figcaption></figure>

| From | To   | Colour             |
| ---- | ---- | ------------------ |
| 0    | 2.3  | `#4CAF50` (green)  |
| 2.3  | 4.5  | `#FFEB3B` (yellow) |
| 4.5  | 7.1  | `#FF9800` (orange) |
| 7.1  | 10.0 | `#F44336` (red)    |

Additional settings:

| Setting       | Value                            |
| ------------- | -------------------------------- |
| Min           | `0`                              |
| Max           | `10`                             |
| Decimals      | `1`                              |
| Units         | `mm/s`                           |
| Title         | `Vibration Severity (ISO 10816)` |
| {% endstep %} |                                  |

{% step %}

### Tri-Axial Vibration Chart

<figure><img src="/files/s5TAzrUqaySE4zatiXxj" alt="" width="357"><figcaption></figcaption></figure>

Add widget → **Charts** → **Time series chart**

Data keys: `plc_rSensorX_vrms`, `plc_rSensorY_vrms`, `plc_rSensorZ_vrms`

<div><figure><img src="/files/iLk4HX8RJiPYvzUHBfRb" alt=""><figcaption></figcaption></figure> <figure><img src="/files/GqbceuPiiyxwe0AK6Bg7" alt=""><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}

### Motor Temperature Trend

<figure><img src="/files/3YogTZb3ZiTAQKgDyb01" alt="" width="355"><figcaption></figcaption></figure>

Similarly, you can also make a trend of Motor Temperature
{% endstep %}

{% step %}

### Vibration Severity Trend Chart

<figure><img src="/files/gLKN2K8Uvl3lItUMFpMb" alt="" width="353"><figcaption></figcaption></figure>

Add widget → **Charts** → **Time series chart**

Data key: `vibration_severity`

Add threshold lines at `2.3`, `4.5`, and `7.1` mm/s so operators can immediately see how close the severity is to each ISO zone boundary.

<figure><img src="/files/ZGMNMKsAXTncJKYMUn5K" alt="" width="563"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Add Alarm Table

<figure><img src="/files/7Ct1Kjj6ert5PnBlFB2u" alt="" width="563"><figcaption></figcaption></figure>

Add widget → **Tables**→ **Alarms table**

| Setting             | Value                                                      |
| ------------------- | ---------------------------------------------------------- |
| Time window         | Use widget time window                                     |
| Alarm source        | Entity Alias > MachineData                                 |
| Alarm Status list   | <p>Active<br>Cleared<br>Acknowledged<br>Unacknowledged</p> |
| Alarm Severity list | <p>Critical<br>Major<br>Warning</p>                        |
| Alarm type list     | Motor Vibration                                            |
| {% endstep %}       |                                                            |

{% step %}

### Final dashboard layout

Arrange the widgets as follows for the clearest operator view:

```
┌─────────────────┬──────────────────────────┬──────────────────────────┐
│ Machine Health  │ Tri-Axial Vibration       │ Motor Temperature Trend  │
│ (colour card)   │ (X/Y/Z time series)       │ (line chart)             │
│                 │                           │                          │
│ Warnings: 0     ├──────────────────────────┼──────────────────────────┤
│                 │ Vibration Severity        │ Vibration Severity       │
│ Critical: 0     │ (trend chart with         │ (ISO 10816 gauge)        │
│                 │  ISO threshold lines)     │                          │
│ Motor image     │                           │                          │
│                 ├───────────────────────────┴──────────────────────────┤
│ Temperature     │ Alarms table (full width)                            │
└─────────────────┴──────────────────────────────────────────────────────┘
```

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FJeHp6035YL84GuBWzJBG%2FAufzeichnung%202026-03-23%20150309.mp4?alt=media&token=b0c1e2f5-9d16-455a-9fa7-52b1426de29a>" %}

{% hint style="success" %}
**Reading order:**&#x20;

The left column gives instant health status. The centre column shows the vibration detail over time. The right column shows the temperature and the ISO-calibrated gauge. The alarms table at the bottom provides a full audit history.
{% endhint %}
{% endstep %}
{% endstepper %}

***

### How It All Connects

Looking back at the full pipeline:

1. The **Balluff BCM sensor** measures tri-axial vibration (X/Y/Z RMS) and temperature continuously
2. The **Balluff IO-Link Master** exposes sensor data over Modbus TCP
3. The **reComputer vPLC** reads registers every scan cycle, byte-swaps Big-Endian floats, and exposes clean `REAL` values via its OPC UA server
4. **Node-RED on the reComputer R1100** polls the OPC UA server every second and publishes a JSON payload to ThingsBoard via MQTT
5. **ThingsBoard Calculated Fields** compute vibration severity (`sqrt(X²+Y²+Z²)`) and classify machine health (HEALTHY / WARNING / CRITICAL / EMERGENCY) in real time, no external scripts needed
6. **Alarm rules** fire when severity crosses ISO 10816 zone boundaries, with structured alarm messages including rounded axis values
7. The **dashboard** gives operators instant visual feedback through a colour-coded health card, ISO-banded gauge, and trend charts

***

## Resources <a href="#download-my-dashboard" id="download-my-dashboard"></a>

#### ThingsBoard Dashboard

{% file src="/files/e8lBXpG6XCS20kEf5TXg" %}

{% hint style="info" %}
To learn how to import a dashboard, kindly refer to the last article here [ThingsBoard (Edge Setup)](/product-reviews/smart-platforms/thingsboard/thingsboard-edge-setup)
{% endhint %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# HiveMQ Edge-to-Cloud AI Pipeline

Anomaly Detection using HiveMQ Cloud, Python (PyOD), and Flask

This article explains the full data pipeline shown in the diagram starting from a PLC on the shopfloor, sending data through HiveMQ Edge and Cloud, into an AI model built with **Python + PyOD**, and finally sending the anomaly result back to the HiveMQ Edge for visualization.

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FN7nrvFnAq1yuJpxLOFcm%2FHiveMQ_Post3.mp4?alt=media&token=fdabc463-593a-40d1-9092-f67facd0188d>" %}

{% hint style="info" %}
Kindly refer to last article to learn how to send factory data to HiveMQ Cloud. This article continues from there to further send data to ML for anomaly detection.
{% endhint %}

## System Overview

This architecture demonstrates how vibration data from a machine is collected at the **OT (Operational Technology)** level, transported securely to the **Cloud**, evaluated using an AI model, and returned to the shop-floor for further action.

It consists of:

1. **Input Layer** – Reading vibration data from a PLC (via OPC UA)
2. **Transport Layer** – Sending data from HiveMQ Edge → HiveMQ Cloud (via MQTT)
3. **AI Layer** – ML server running Python + Flask + PyOD locally on the computer
4. **Output Layer** – Returning anomaly alerts via MQTT → HiveMQ Edge → PLC (optional)

***

## Step-by-Step Breakdown of the Pipeline

### **1. Input Layer — PLC to HiveMQ Edge (OPC UA)**

* A Siemens S7-1500 PLC measures **vibration (simulated)** from the machine.
* This data is exposed through **OPC UA**.
* HiveMQ Edge connects to the PLC's OPC UA server.
* It maps the OPC UA tag (e.g., `vibration`) to an MQTT topic:

```
machine/s71500/rVib
```

> Industrial data becomes IIoT data.

***

### **2. Transport Layer — HiveMQ Edge to HiveMQ Cloud (MQTT)**

HiveMQ Edge publishes the MQTT message (`machine/s71500/vib`) to **HiveMQ Cloud**, which acts as a central cloud broker.

Benefits:

* Low latency
* Very small message size → suitable for industrial IoT
* Secure TLS transport and easy to scale

{% hint style="info" %}
Learn more about that in our earlier posts on HiveMQ where you will learn the complete workflow: [PLC to Cloud via HiveMQ (Edge + Cloud) — OPC UA → MQTT → Confluent](/product-reviews/smart-platforms/hivemq/plc-to-cloud-via-hivemq-edge-+-cloud-opc-ua-mqtt-confluent)
{% endhint %}

***

### 3. AI Layer — ML server running Python + Flask + PyOD locally on the compute

This is where the anomaly detection happens. Let's first understand what is Anomaly detection and why we need it

#### What is Anomaly detection?

**Anomaly detection** is the process of identifying data points or behavior that deviate from what’s considered *normal*. In simple terms, it spots when something unusual is happening.

In **Machine Learning**, anomaly detection helps models understand patterns and flag unexpected behaviour without needing labels. In **IIoT**, it's essential because machines generate huge amounts of real-time data, and even small deviations can signal issues like equipment failure, quality defects, cyber-attacks, or unsafe operating conditions.

#### **Why we need it:**

* Detect problems early before they become costly
* Improve uptime and reliability
* Enhance safety and Reduce maintenance costs

#### 🧠 PyOD — Python Outlier Detection Library

**PyOD** is a widely-used ML library that provides 40+ algorithms for anomaly detection, such as:

* Isolation Forest (IForest)
* AutoEncoders
* One-Class SVM
* LOF (Local Outlier Factor)

In the example, **Isolation Forest (IForest)** is used. It learns what “normal vibration” looks like from training data:

```python
train = np.array([[0.23], [0.25], [0.21], [0.29]])
model = IForest()
model.fit(train)
```

When new data comes, PyOD predicts:

* **0 → Normal**
* **1 → Anomaly**

**Learn more about Pyod here:** [**https://pyod.readthedocs.io/en/latest/**](https://pyod.readthedocs.io/en/latest/)

#### **Installing Pyod and testing Anomaly detection**

In our example, the Pyod has been installed in the windows computer. The following are the steps:

{% stepper %}
{% step %}

#### Install pyod on Windows PC

{% hint style="info" %}
Make sure Python is installed in your computer. In our case, we are using Python 3. To install Python visit here: <https://www.python.org/downloads/>
{% endhint %}

```
pip3 install pyod
```

{% endstep %}

{% step %}

#### Create a python file for testing:

`test_pyod.py`
{% endstep %}

{% step %}

#### Add the following code in that

```python
from pyod.models.iforest import IForest
import numpy as np

# training data: only normal vibration history
train = np.array([[0.23], [0.25], [0.21], [0.29]])

model = IForest()
model.fit(train)

# real-time vibration input
value = 0.45 #change this value to see different result.
prediction = model.predict([[value]])[0]

if prediction == 1:
    print("Anomaly detected!")
else:
    print("Normal")

```

{% endstep %}

{% step %}

#### Run the Python file

```shellscript
python test_pyod.py
```

{% endstep %}

{% step %}

#### Validate the output

‘Anomaly detected’ or ‘Normal’ based on the value sent in the code (0.45)
{% endstep %}
{% endstepper %}

#### Anomaly detection using Pyod and Node-RED

Now, we are going to test the code using Node-RED. In this case, we setup a flask server in Node-RED so that we can execute the Python code using API. This makes it easy to send data to the Python file and get anomaly results as feedback.

{% hint style="info" %}
Make sure latest version of Node-RED and Python is installed in your system.&#x20;

* To install Node-RED visit here: <https://nodered.org/>
* To install Python visit here: <https://www.python.org/downloads/>
  {% endhint %}

Once, the Node-RED is installed proceed with the following steps:

{% stepper %}
{% step %}

#### Convert Your Python Code into a Simple API Server.

We will not run Python file directly from Node-RED, we will create a Python web API for data exchange.&#x20;

Create a new Python file named '**server.py**' with the following code:

{% code overflow="wrap" lineNumbers="true" expandable="true" %}

```python
from flask import Flask, request, jsonify
from pyod.models.iforest import IForest
import numpy as np

app = Flask(__name__)

# Train model once at startup
train = np.array([[0.23], [0.25], [0.21], [0.29]])
model = IForest()
model.fit(train)

@app.route("/predict", methods=["POST"])
def predict():
    data = request.json
    value = float(data["value"])  # vibration input

    prediction = model.predict([[value]])[0]

    return jsonify({
        "value": value,
        "prediction": int(prediction),
        "status": "Anomaly" if prediction == 1 else "Normal"
    })

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
```

{% endcode %}
{% endstep %}

{% step %}

#### Install Flask

```shellscript
pip install flask
```

{% endstep %}

{% step %}

#### Run your Python Server

```shellscript
python server.py
```

{% endstep %}

{% step %}

#### Validate

You should see the following:

<figure><img src="/files/zMyDf7tFLRaaojkKEtiA" alt=""><figcaption></figcaption></figure>

Your anomaly detection API is now LIVE at: <http://localhost:5000/predict>
{% endstep %}

{% step %}

#### Start Node-RED and test the Anomaly detection

You can use the '**http request node**' in Node-RED to send sample data and fetch anomaly results as shown below.&#x20;

<figure><img src="/files/7XhteKdDw8faP3PWJeij" alt=""><figcaption></figcaption></figure>

Kindly check the reference Node-RED flow below:

{% code overflow="wrap" expandable="true" %}

```json
[
    {
        "id": "53bf0f485d74978b",
        "type": "tab",
        "label": "Flow 3",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "05ded4d2341631a0",
        "type": "http request",
        "z": "53bf0f485d74978b",
        "name": "",
        "method": "POST",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://localhost:5000/predict",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 530,
        "y": 80,
        "wires": [
            [
                "7b1ef153885b1894"
            ]
        ]
    },
    {
        "id": "4abe4b4dca5e520e",
        "type": "function",
        "z": "53bf0f485d74978b",
        "name": "function 3",
        "func": "msg.headers = { \"Content-Type\": \"application/json\" };\nmsg.payload = { value: msg.payload };\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 340,
        "y": 80,
        "wires": [
            [
                "05ded4d2341631a0"
            ]
        ]
    },
    {
        "id": "7b1ef153885b1894",
        "type": "debug",
        "z": "53bf0f485d74978b",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 700,
        "y": 80,
        "wires": []
    },
    {
        "id": "301488acacb31208",
        "type": "inject",
        "z": "53bf0f485d74978b",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "0.45",
        "payloadType": "num",
        "x": 150,
        "y": 80,
        "wires": [
            [
                "4abe4b4dca5e520e"
            ]
        ]
    },
    {
        "id": "0f591249346fc88a",
        "type": "inject",
        "z": "53bf0f485d74978b",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "0.25",
        "payloadType": "num",
        "x": 150,
        "y": 120,
        "wires": [
            [
                "4abe4b4dca5e520e"
            ]
        ]
    }
]
```

{% endcode %}
{% endstep %}
{% endstepper %}

***

#### Testing Anomaly detection with PLC Data

Now, let's use the above example and sends the PLC data to the Python server to get anomaly results.&#x20;

{% hint style="info" %}
For the sake of demonstration, we are considering the normal values within the range $$0.0∼5.0$$ and anomalies outside this range. So, in our Python code, we have created a dataset of $$500$$ samples in the range of $$0.0$$ to $$5.0$$. Our model will learn from this dataset, as shown in the code below.
{% endhint %}

{% stepper %}
{% step %}

#### Update your Python code in the server.py file

The code trains an anomaly detection model, exposes it through a REST API, and lets you retrain the model using real machine data.

{% code overflow="wrap" lineNumbers="true" expandable="true" %}

```python
from flask import Flask, request, jsonify
from pyod.models.iforest import IForest
from sklearn.preprocessing import StandardScaler
import numpy as np

app = Flask(__name__)

# =========================================================
# 1. TRAIN MODEL ON REALISTIC NORMAL VIBRATION DISTRIBUTION
# =========================================================

# Simulate "normal" vibration: around 2.0 + noise(-3 to +3)
# That gives ~ 0 to 5 mm/s range
normal_values = np.random.uniform(0.0, 5.0, 500)   # 500 samples
normal_values = normal_values.reshape(-1, 1)

# Scale the training data (important for broader vibration ranges)
scaler = StandardScaler()
normal_scaled = scaler.fit_transform(normal_values)

# Train Isolation Forest
model = IForest(contamination=0.05)  # 5% anomaly expected
model.fit(normal_scaled)


# =========================================================
# 2. API ENDPOINT: PREDICT ANOMALY
# =========================================================
@app.route("/predict", methods=["POST"])
def predict():
    data = request.json
    value = float(data["value"])

    # Scale incoming data
    scaled_value = scaler.transform([[value]])

    # Raw prediction: 1 = anomaly, 0 = normal
    prediction = int(model.predict(scaled_value)[0])

    # Anomaly score (higher → more anomaly)
    score = float(model.decision_function(scaled_value)[0])

    return jsonify({
        "input_value": value,
        "scaled_value": scaled_value[0][0],
        "anomaly_score": score,
        "prediction": prediction,
        "status": "Anomaly Detected" if prediction == 1 else "Normal Behaviour"
    })


# =========================================================
# 3. OPTIONAL — RETRAIN USING DATA FROM CLIENT (Node-RED)
# =========================================================
@app.route("/retrain", methods=["POST"])
def retrain():
    data = request.json
    new_samples = np.array(data["samples"]).reshape(-1, 1)

    global scaler, model

    scaler = StandardScaler()
    scaled = scaler.fit_transform(new_samples)

    model = IForest(contamination=0.05)
    model.fit(scaled)

    return jsonify({"message": "Model retrained successfully", "samples_used": len(new_samples)})


# =========================================================
# 4. RUN SERVER
# =========================================================
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

```

{% endcode %}

This script creates a small **AI-powered anomaly detection API** using Flask and the PyOD Isolation Forest model.

1. **It generates normal vibration data** (0–5 mm/s) and uses it to train an Isolation Forest model.
2. **It scales all vibration values** using StandardScaler so the model can understand them correctly.
3. **It exposes a `/predict` API endpoint** where you send one vibration value, and the server returns:
   * Normal or Anomaly
   * Anomaly score
   * Scaled value
4. **It provides a `/retrain` endpoint** that allows you to send new vibration samples (from Node-RED or a PLC) and retrain the model on the fly.
5. **Flask runs the server on port 5000**, making it easy to integrate with IIoT systems.

Learn more about this code here: [Anomaly detection Code Explanation](/product-reviews/smart-platforms/hivemq/hivemq-edge-to-cloud-ai-pipeline/anomaly-detection-code-explanation)&#x20;
{% endstep %}

{% step %}

#### Update the Node-RED flow

Now we need to subscribe the following HiveMQ Cloud topic to get the LIVE vibration data:

```
hivemq-edge/machine/s71500/rVib
```

<figure><img src="/files/M6ovmudQeJq1mKxjt6Ey" alt=""><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

> Every time vibration data arrives from HiveMQ Cloud → the ML server receives it, runs inference, and give the result back to Node-RED

***

### **4. Output Layer** – Returning anomaly alerts via MQTT → HiveMQ Edge → PLC (optional)

**Now we need to send the result back to HiveMQ Edge, visualize it on the dashboard or sends to the PLC for further action.**

{% stepper %}
{% step %}

#### Add MQTT out node in the flow

We will take another MQTT topic to filter and publish the result

```
hivemq-edge/machine/s71500/anomaly
```

<figure><img src="/files/OOaPUFdbwXR3t2129bIE" alt=""><figcaption></figcaption></figure>

The following flow can be used as a reference.

{% code overflow="wrap" expandable="true" %}

```json
[
    {
        "id": "1ad2c5724dad60ec",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "2e10e2177a83dbbf",
        "type": "http request",
        "z": "1ad2c5724dad60ec",
        "name": "",
        "method": "POST",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://localhost:5000/predict",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 570,
        "y": 80,
        "wires": [
            [
                "c3746a81c58e797a"
            ]
        ]
    },
    {
        "id": "1d57a237256e69e7",
        "type": "function",
        "z": "1ad2c5724dad60ec",
        "name": "function 1",
        "func": "msg.headers = { \"Content-Type\": \"application/json\" };\nmsg.payload = { value: msg.payload.value };\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 400,
        "y": 80,
        "wires": [
            [
                "2e10e2177a83dbbf"
            ]
        ]
    },
    {
        "id": "ecd705d7eabc8086",
        "type": "mqtt in",
        "z": "1ad2c5724dad60ec",
        "name": "",
        "topic": "hivemq-edge/machine/s71500/rVib",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "08f8856327f4fe37",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 160,
        "y": 80,
        "wires": [
            [
                "1d57a237256e69e7"
            ]
        ]
    },
    {
        "id": "67d96c79df053896",
        "type": "mqtt out",
        "z": "1ad2c5724dad60ec",
        "name": "",
        "topic": "hivemq-edge/machine/s71500/anomaly",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "08f8856327f4fe37",
        "x": 600,
        "y": 160,
        "wires": []
    },
    {
        "id": "c3746a81c58e797a",
        "type": "function",
        "z": "1ad2c5724dad60ec",
        "name": "function 2",
        "func": "msg.payload = msg.payload.status;\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 300,
        "y": 160,
        "wires": [
            [
                "67d96c79df053896"
            ]
        ]
    },
    {
        "id": "08f8856327f4fe37",
        "type": "mqtt-broker",
        "name": "",
        "broker": "1eba33276f3f4d2b9852f78bf6ab2880.s1.eu.hivemq.cloud",
        "port": "8883",
        "tls": "",
        "clientid": "",
        "autoConnect": true,
        "usetls": true,
        "protocolVersion": 4,
        "keepalive": 60,
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]
```

{% endcode %}
{% endstep %}

{% step %}

#### Bridge the HiveMQ Cloud MQTT topic with HiveMQ Edge MQTT topic

Go to MQTT bridge in HiveMQ Edge and add a remote subscription in your current bridge as shown below:

<figure><img src="/files/PEjrCUv9Ua55ocSswdft" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/THKGag1h29KxsJeaQa7H" alt="" width="375"><figcaption></figcaption></figure>

Now navigate to Broker Configuration and 'Enable loop prevention'. This will prevent looping of data flow

<figure><img src="/files/QR9Gffxrya8GEdhq11ct" alt="" width="375"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### Visualize Anomaly in HiveMQ Edge

Now that the anomaly arrives to MQTT Edge, you can visualize it with tools like Node-RED as shown below:

<figure><img src="/files/dRlF8zLznYXiPHae86WK" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ZJS6Oi6FSFX8XzHcoMKu" alt="" width="321"><figcaption></figcaption></figure>

{% hint style="info" %}
You can further sends the anomaly results back to PLC via OPC UA.
{% endhint %}
{% endstep %}
{% endstepper %}

***

## Complete Workflow

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FvPGMMRYPhiqsUXnsEKhl%2FHiveMQ%20Anomaly%20detection.mp4?alt=media&token=730bd29b-d752-4e25-976d-e49e406924bd>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Anomaly detection Code Explanation

Overview of the Anomaly Detection API (Flask + PyOD)

This page explains how the provided Python script works. The application uses Flask to expose an HTTP API and PyOD’s Isolation Forest model to detect anomalies in vibration data. It is designed for learners, developers, and IIoT practitioners who want to integrate machine learning into their systems (PLC, Node-RED, edge devices, etc.).

### 1. Model Training (Normal Vibration Simulation)

The script begins by simulating “normal” vibration data to train the machine learning model.

```python
normal_values = np.random.uniform(0.0, 5.0, 500)
normal_values = normal_values.reshape(-1, 1)
```

* This generates 500 vibration samples between 0 and 5 mm/s.
* These represent healthy/normal machine behaviour.

#### Scaling the Data

```python
scaler = StandardScaler()
normal_scaled = scaler.fit_transform(normal_values)
```

The data is scaled using `StandardScaler`, which helps the model handle different ranges of vibration input by normalizing values to have:

* mean = 0
* standard deviation = 1

#### Training the Isolation Forest Model

```python
model = IForest(contamination=0.05)
model.fit(normal_scaled)
```

* Isolation Forest is an unsupervised anomaly detection algorithm.
* `contamination=0.05` means we expect approximately 5% of the data to be anomalies.
* This model learns what “normal” vibration looks like.

***

### 2. Prediction API Endpoint (`/predict`)

This endpoint accepts a POST request with a vibration value and returns whether it is normal or anomalous.

Example request:

```json
{
  "value": 3.2
}
```

Processing steps:

1. Read the input vibration value.
2. Scale the value using the same scaler as the training data.
3. Run the Isolation Forest model to compute:
   * prediction (0 = normal, 1 = anomaly)
   * anomaly score

Example returned JSON:

```json
{
  "input_value": 3.2,
  "scaled_value": 0.12,
  "anomaly_score": -0.045,
  "prediction": 0,
  "status": "Normal Behaviour"
}
```

This makes it easy to connect the API to a PLC, Node-RED dashboard, or MQTT workflow.

***

### 3. Retraining Endpoint (`/retrain`)

This optional endpoint allows you to retrain the model using new samples, for example from live machine data.

Example request:

```json
{
  "samples": [0.5, 1.1, 2.0, 3.3, 1.8]
}
```

What happens internally:

1. The data is reshaped and scaled again.
2. A new Isolation Forest model is trained.
3. The global `scaler` and `model` variables are updated.

This feature is useful when:

* Machine behaviour changes over time
* You want to build a personalized model based on real data
* You need continuous improvement of detection accuracy

Response example:

```json
{
  "message": "Model retrained successfully",
  "samples_used": 5
}
```

***

#### 4. Running the Flask Server

```shellscript
app.run(host="0.0.0.0", port=5000)
```

* The server runs on port 5000.
* `0.0.0.0` makes it accessible on your local network.
* Ideal for integration with Node-RED, PLCs, or industrial dashboards.

***

### Summary

```
                ┌─────────────────────┐
                │   External Device   │
                │  (PLC / Sensor /    │
                │   Node-RED / API)   │
                └─────────┬───────────┘
                          │  POST /predict
                          │  {"value": 3.2}
                          ▼
               ┌──────────────────────────┐
               │        Flask API         │
               │    (server.py running)   │
               └──────────┬───────────────┘
                          │
                          │
          ┌───────────────┴────────────────┐
          │   Preprocessing Layer           │
          │   (StandardScaler)              │
          │                                   │
          │ - Normalizes incoming vibration   │
          │   values                          │
          │ - Ensures correct ML model input  │
          └───────────────┬──────────────────┘
                          │ scaled_value
                          ▼
               ┌──────────────────────────┐
               │  Isolation Forest Model  │
               │       (PyOD IForest)     │
               ├──────────────────────────┤
               │ Learns "normal" pattern  │
               │ Detects anomalies         │
               │ Generates anomaly score   │
               └──────────┬───────────────┘
                          │ prediction + score
                          ▼
                 ┌──────────────────┐
                 │ JSON Response    │
                 │                  │
                 │ {                │
                 │  "prediction":0  │
                 │  "status":"Normal"│
                 │  "score":-0.04   │
                 │ }                │
                 └──────────────────┘


──────────────────────────────────────────────────────────────────────
```

* Flask provides the API endpoints (`/predict` and `/retrain`).
* PyOD’s Isolation Forest detects anomalies in vibration values.
* StandardScaler normalizes the data for better model performance.
* `/predict` checks if a vibration value is normal or abnormal.
* `/retrain` lets you update the model using new machine data.
* This setup is ideal for IIoT, predictive maintenance, and real-time monitoring.


# Secure OT/IT Data Integration Using HiveMQ Edge and Site DMZ

Typical enterprise OT/IT integration using HiveMQ Edge and Site DMZ

## System Overview

In industrial environments, securely moving data from OT to IT is not about connecting everything together.&#x20;

> It’s about **placing the right components in the right network layers**.

Most enterprises deploy HiveMQ in a **layered architecture**, aligned with the automation pyramid and network zones. This article explains a typical OT/IT integration pattern using **HiveMQ Edge** and a **Site DMZ broker (Level 3.5)**.

<figure><img src="/files/N0LGNEXNDonik2YUmV3o" alt=""><figcaption></figcaption></figure>

### 1.  OT / Device Layer

At the lowest level, PLCs and field devices generate raw machine data such as:

* vibration
* temperature
* speed
* status signals

This data is typically exposed via industrial protocols such as **OPC UA**.

At this stage:

* Data stays inside the OT network
* No IT or cloud systems access PLCs directly

***

### 2.  Edge Integration Layer

**HiveMQ Edge** runs close to the machines and acts as the OT integration point.

Typical responsibilities of HiveMQ Edge include:

* Connecting to PLCs via OPC UA
* Mapping OT data to MQTT topics
* Filtering, normalizing, and buffering data
* Publishing data northbound using MQTT

Only selected and structured data leaves the OT layer.

Example topic mapping:

```
OPC UA Node   →   MQTT Topic
PLC vibration →   machine/s71500/vibration
```

***

### 3.  Site DMZ / Level 3.5

A **self-hosted HiveMQ broker** is deployed at the site level, often referred to as **Level 3.5** or the **DMZ**.

Important clarification:

* HiveMQ does not have a special “DMZ mode”
* The DMZ is enforced by **network architecture**, firewalls, and zones
* The broker simply runs **inside** that DMZ

This broker acts as:

* The aggregation point for multiple Edge instances
* The controlled handover between OT and IT

***

### 4.  IT / Enterprise Layer

From the Site DMZ broker, data can be consumed by:

* analytics platforms
* dashboards
* AI / ML systems
* ERP or MES applications
* cloud services

IT systems subscribe to MQTT topics exposed by the DMZ broker — **not** to PLCs or Edge devices.

***

### Key Security Principle

> **OT never connects directly to IT.**\
> The Site DMZ broker is the single, controlled handover point.

This approach:

✅ Preserves OT isolation\
✅ Scales across sites and factories\
✅ Aligns with UNS and enterprise security practices

***

## Summary

HiveMQ Edge and a Site DMZ broker form a clean and secure OT/IT integration pattern:

* Edge handles OT complexity
* The DMZ broker enforces architectural separation
* IT systems consume data without exposing the OT network

This layered approach mirrors how most enterprises deploy HiveMQ within their UNS and IIoT strategies.

***

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Coreflux

The most versatile and user-friendly IoT data pipeline in the industry.

In the following articles, I will show you some use cases for the Coreflux MQTT broker. Feel free to use my project and resources for your application.


# Coreflux MQTT Broker

Real-time vibration severity monitoring using LoT scripting + Python

## Overview

This guide walks you through setting up the Coreflux MQTT Broker on a Revolution Pi (ARM64) industrial edge device, deploying LOT (Language of Things) actions from VS Code, and running Python-based vibration severity calculations directly inside the MQTT broker with no cloud dependency.

### Data flow

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FDEsbpF3fUarx0seaxn7C%2FCoreflux.mp4?alt=media&token=e018d5e2-6777-4dbe-b1d2-5d09b9ab0cde>" %}

## Prerequisites

### Hardware

* Revolution Pi (ARM64) or any edge device with Ethernet. Learn abou the hardware requirement here: <https://docs.coreflux.org/quick-start/installation>
* Network connection between your dev PC and RevPi
* Vibration sensor with IO-Link (or simulated data)

### Software (Development PC)

* Visual Studio Code
* [LoT Language](https://docs.coreflux.org/lot-language/introduction) Support by Coreflux extension (VS Code marketplace)
* Python 3.11.9 from python.org (Not Microsoft Store version, see troubleshooting)

### Software (Revolution Pi)

* [Coreflux MQTT Broker ](https://docs.coreflux.org/)for Linux ARM64
* Python 3.11.x (installed via apt)
* python3.11-dev package
* Node-RED (optional, for visualization)

***

### 1. Installing Coreflux on Revolution Pi

{% stepper %}
{% step %}

#### Download and Extract

Download the Linux ARM64 build of Coreflux MQTT Broker from coreflux.org. Transfer it to your RevPi via SCP or download directly:

```shellscript
# On RevPi — create install directory
mkdir ~/coreflux
cd ~/coreflux

# Extract the downloaded zip
unzip CorefluxMQTTBroker_linux-arm64_1.10.0.zip

# Make binary executable
chmod +x CorefluxMQTTBroker

```

{% endstep %}

{% step %}

#### Install the Coreflux MQTT Broker

The installation instructions are given on this page: <https://docs.coreflux.org/quick-start/installation#raspberry-pi>

Start the broker to verify it works:

```shellscript
cd ~/coreflux
sudo ./CorefluxMQTTBroker
```

You should see the broker start and listen on port 1883. Press Ctrl+C to stop after confirming startup.

{% hint style="info" %}
Default Credentials

The default Coreflux broker credentials are username: root, password: coreflux. These are required when connecting from VS Code or MQTT clients.
{% endhint %}
{% endstep %}

{% step %}

### Install VS Code&#x20;

Install the open source code editor i.e., VS Code, on your computer: <https://code.visualstudio.com/>
{% endstep %}

{% step %}

### Install LoT extension in VS Code

LoT (Language of Things) is a human-readable language for IoT automation. It uses near-English syntax to define logic, data structures, and integrations—all executed directly within the Coreflux MQTT broker.\
\
The LoT extension lets you interact with the Coreflux MQTT broker from VS Code. To install LoT, go to the extension in VS Code and search for LoT.

<figure><img src="/files/V92ir14cBXQlm4XHstbg" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Learning LoT

To learn how LoT interacts with Coreflux MQTT Broker, check this repository, which has many sample codes and exercises: <https://github.com/CorefluxCommunity/Language-Of-Things-Training/tree/main>
{% endstep %}

{% step %}

#### Configure VS Code Connection

In your LoT project folder, create or edit the .broker file with credentials embedded in the URL:

```shellscript
mqtt://root:coreflux@<RevPi-IP>:1883
#username: root, password: coreflux
```

{% hint style="warning" %}
Authentication Required

Without credentials in the .broker file, the VS Code extension will connect but receive PermissionDenied errors when trying to subscribe to $SYS/Coreflux/ system topics. This causes the 'Entity not found on broker' error in the LOT notebook.
{% endhint %}
{% endstep %}
{% endstepper %}

***

### 2. Setting Up Python Runtime on Revolution Pi

Coreflux uses an embedded Python runtime located in \~/coreflux/python\_runtime/. On Linux ARM64, this requires manually copying the system Python shared libraries into this folder.

{% stepper %}
{% step %}

#### Install Required Python Packages

```shellscript
sudo apt update
sudo apt install python3.11 python3.11-dev python3.11-full -y
```

{% hint style="info" %}
Why python3.11-dev?

The -dev package installs the shared library files (libpython3.11.so) that embedded runtimes need to load Python via the C API. Without it, the broker finds the python\_runtime folder but cannot initialize Python.
{% endhint %}
{% endstep %}

{% step %}

### Find the Shared Library Files

{% code overflow="wrap" expandable="true" %}

```shellscript
find /usr/lib -name "libpython3.11*" 2>/dev/null

# Expected output:
# /usr/lib/aarch64-linux-gnu/libpython3.11.so.1
# /usr/lib/aarch64-linux-gnu/libpython3.11.so.1.0
# /usr/lib/python3.11/config-3.11-aarch64-linux-gnu/libpython3.11.so

```

{% endcode %}
{% endstep %}

{% step %}

### Copy Files to python\_runtime

```shellscript
# Clear existing contents
sudo rm -rf /home/pi/coreflux/python_runtime/*

# Copy Python executable
sudo cp /usr/bin/python3 /home/pi/coreflux/python_runtime/python

# Copy Python standard library
sudo cp -r /usr/lib/python3.11 /home/pi/coreflux/python_runtime/

# Copy shared libraries (critical — broker loads these at runtime)
sudo cp /usr/lib/aarch64-linux-gnu/libpython3.11.so.1 /home/pi/coreflux/python_runtime/
sudo cp /usr/lib/aarch64-linux-gnu/libpython3.11.so.1.0 /home/pi/coreflux/python_runtime/

```

{% endstep %}

{% step %}

#### Confirm Python Loads at Broker Startup

Start the broker and look for these lines in the output:

<pre class="language-shellscript"><code class="lang-shellscript"><strong>sudo ./CorefluxMQTTBroker
</strong>
# Look for:
# INF  Embedded Python runtime initialized at: /home/pi/coreflux/python_runtime
# INF  Python runtime initialized successfully    &#x3C;-- this is what we want
# INF  Python Entity Provider initialized
</code></pre>

{% hint style="success" %}
&#x20;Python Working

When you see 'Python runtime initialized successfully' instead of 'Python runtime not available,  scripts disabled', the Python integration is ready.
{% endhint %}
{% endstep %}
{% endstepper %}

***

### 3. Troubleshooting

#### 3.1 Python Version Compatibility

{% hint style="warning" %}
Use Python 3.11 Only

Coreflux 1.10.0 is only compatible with Python 3.11. Using Python 3.12, 3.13, or 3.14 will cause 'Python runtime not available' even if all files are correctly copied. Always verify with: python3 --version
{% endhint %}

#### 3.2 Windows — Microsoft Store Python

On Windows, if Python is installed via the Microsoft Store, the where Python command returns:

```
C:\Users\YourName\AppData\Local\Microsoft\WindowsApps\python.exe
```

{% hint style="warning" %}
&#x20;Microsoft Store Python Incompatible

The Microsoft Store Python is a stub launcher — it does not contain python311.dll or the Lib/ folder that Coreflux needs. Always install Python from python.org using the Windows installer (64-bit). Download: <https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe>
{% endhint %}

#### 3.3 Windows- Copying Python to python\_runtime

After installing Python 3.11.9 from python.org, copy the full installation into the broker folder. This is in case you are running Coreflux Broker on Windows

```shellscript
# First confirm real Python path (should NOT be WindowsApps)
where python

# Copy to broker runtime folder
xcopy /E /I "C:\Users\YourName\AppData\Local\Programs\Python\Python311\*" "C:\Downloads\CorefluxMQTTBroker_win-x64_1.10.0\python_runtime\"

```

#### 3.4 Port 1883 Already in Use (Linux)

If you see 'MQTT Port 1883 is in use by unknown process', another instance of Coreflux is already running (possibly managed by pm2 or systemd):

```shellscript
# Find what is using port 1883
sudo lsof -i :1883

# Kill the process (use the PID shown)
sudo kill -9 <PID>

# If managed by pm2
pm2 stop all

# If managed by systemd
sudo systemctl stop coreflux
```

#### 3.5 'Entity Not Found on Broker' Error

This error appears in the LoT notebook when clicking the play button, but the action has never been deployed, or the broker has restarted and lost the action. The play button in a .lotnb file deploys the action to the broker; it does not auto-persist between broker restarts unless the action file is saved in the broker's persistent storage location.

{% hint style="info" %}
Deployment Tip

After restarting the broker, re-run all cells in your .lotnb file using 'Run All' to redeploy all actions.
{% endhint %}

***

### 4. Vibration Severity Example

#### 4.1 The Python Script- VibrationCalc.py

Create this file in your VS Code project. It will be deployed to the broker's python\_scripts folder:

```shellscript
# Script Name: VibrationCalc
import math

# Calculate 3-axis vibration magnitude using Euclidean distance formula
def sqrt_sum_of_squares(x, y, z):
    try:
        result = math.sqrt(float(x)**2 + float(y)**2 + float(z)**2)
        return result
    except (ValueError, TypeError):
        return 0  # Return safe default if sensor sends bad/missing data
```

{% hint style="info" %}
ISO 10816 Reference

The output of this function is vibration severity in mm/s RMS. According to ISO 10816: Zone A (0-0.7 mm/s) = excellent, Zone B (0.7-1.8) = acceptable, Zone C (1.8-4.5) = monitor, Zone D (>4.5) = danger.
{% endhint %}

#### 4.2 The LOT Action

Create a new .lotnb file in VS Code with this LOT action code:

```shellscript
DEFINE ACTION OpenPLC
ON EVERY 1 SECONDS DO
    # Pull latest RMS vibration readings from MQTT topics every second
    SET "x_vrms" WITH (GET TOPIC "X_VRMS" AS DOUBLE)
    SET "y_vrms" WITH (GET TOPIC "Y_VRMS" AS DOUBLE)
    SET "z_vrms" WITH (GET TOPIC "Z_VRMS" AS DOUBLE)

    # Hand off all 3 axes to Python and get back a single severity score
    CALL PYTHON "VibrationCalc.sqrt_sum_of_squares"
        WITH ({x_vrms}, {y_vrms}, {z_vrms})
        RETURN AS {vibration_severity}

    # Push the combined severity score out for dashboards/alerts to consume
    PUBLISH TOPIC "output/vibration_severity" WITH {vibration_severity}
```

#### 4.3 Deploy from VS Code

1. Open the .lotnb file in VS Code
2. Confirm the status bar shows 'MQTT: Connected to mqtt://\<RevPi-IP>:1883.'
3. Enter your user credentials:
   1. Username: root
   2. Password: coreflux
4. Click the ▶ play button on the LOT action cell to deploy
5. Check the COREFLUX ENTITIES panel — the action should appear
6. Publish test messages to X\_VRMS, Y\_VRMS, Z\_VRMS topics
7. Subscribe to output/vibration\_severity to see results

<figure><img src="/files/hvm2nFfc5kYS12gtQSIW" alt="" width="563"><figcaption></figcaption></figure>

#### 4.4 Test with MQTT Client

In the following example, we are reading actual vibration data via OPC UA. You can just replace the vibration data source in the flow for your use-case.

The source code for this flow is shared in the resource section.

<figure><img src="/files/m0LK4JI6QxbAnFFy2WYB" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="/files/PDML9mw4OWPFS8ub9DyE" alt="" width="563"><figcaption></figcaption></figure>

#### 4.5 ISO 10816 Severity Classification Table

<table data-header-hidden><thead><tr><th width="99.66668701171875">Zone</th><th width="138.6666259765625">RMS (mm/s)</th><th width="144.6666259765625">Classification</th><th>Action</th></tr></thead><tbody><tr><td>Zone</td><td>RMS (mm/s)</td><td>Classification</td><td>Action</td></tr><tr><td>A</td><td>0 – 0.7</td><td>Excellent</td><td>New or recently serviced machine</td></tr><tr><td>B</td><td>0.7 – 1.8</td><td>Acceptable</td><td>Normal long-term operation</td></tr><tr><td>C</td><td>1.8 – 4.5</td><td>Monitor</td><td>Tolerable short-term, investigate</td></tr><tr><td>D</td><td>> 4.5</td><td>Danger</td><td>Shutdown recommended immediately</td></tr></tbody></table>

***

### 5. Network Configuration on Revolution Pi

#### &#xD;5.1 Check Current IPs

```shellscript
hostname -I
ip addr show | grep "inet "
```

#### &#xD;5.1 Assign Static IP to eth1

If you need to assign a static IP to the second Ethernet port (e.g. for direct connection to a PLC or IO-Link master):

```shellscript
# Create network config file
sudo nano /etc/network/interfaces.d/eth1


# Add these lines:
auto eth1
iface eth1 inet static
    address 192.168.100.10
    netmask 255.255.255.0
```

```shellscript
# If ifup does not apply the config, use ip commands directly:
sudo ip addr flush dev eth1
sudo ip addr add 192.168.100.10/24 dev eth1
sudo ip link set eth1 up

# Verify
ip addr show eth1
```

### 6. Managing the Coreflux Broker

#### 6.1 Start with Visible Logs

```shellscript
cd ~/coreflux
sudo ./CorefluxMQTTBroker 2>&1 | tee coreflux.log
```

#### 6.2 Run in Background (pm2)

```shellscript
# Start with pm2
pm2 start ./CorefluxMQTTBroker --name coreflux
pm2 save

# View status
pm2 status

# View logs
pm2 logs coreflux

# Stop
pm2 stop coreflux

```

#### 6.3 Run in Background (pm2)

```shellscript
# Check if broker is running and on which port
sudo lsof -i :1883

# Kill specific PID
sudo kill -9 <PID>

# Kill all instances
sudo pkill -f CorefluxMQTTBroker

```

## Resources:

#### Node-RED flow

{% file src="/files/LC4WmUWCqAq72nbrK3wA" %}

## Quick Reference

| Item                               | Value / Command                                       |
| ---------------------------------- | ----------------------------------------------------- |
| Broker port                        | 1883                                                  |
| Default credentials                | root / coreflux                                       |
| .broker file format                | mqtt://root:coreflux@\<IP>:1883                       |
| Python version (required)          | 3.11.x — do NOT use 3.12+                             |
| python\_runtime location (Linux)   | /home/pi/coreflux/python\_runtime/                    |
| python\_runtime location (Windows) | CorefluxMQTTBroker\_win-x64\_1.10.0\python\_runtime\\ |
| Key apt package                    | python3.11-dev                                        |
| Check broker port                  | sudo lsof -i :1883                                    |
| View broker logs                   | sudo ./CorefluxMQTTBroker 2>&1 \| tee coreflux.log    |
| Deploy action from VS Code         | Click ▶ play button on .lotnb cell                    |
| Output topic                       | output/vibration\_severity                            |


# thin-edge.io

In this article, I’ll guide you step-by-step through thin-edge.io - a lightweight, open-source edge IoT framework designed for resource-constrained devices.

## Introducing thin-edge.io - The open edge IoT Framework

* 🔧 **thin-edge.io** is an open-source framework designed for **resource-constrained devices** with **<16 MB memory** and **low CPU power**, enabling remote monitoring, configuration, and firmware management.
* 🔐 The framework utilizes **X509 certificates** and **MQTT** for secure communication, making it suitable for industrial IoT applications requiring robust security measures.
* 📊 **thin-edge.io** integrates seamlessly with **Cumulocity**, an IoT platform that offers **device management**, **data analytics**, and **alarm management** capabilities through a user-friendly web interface.

## Video Review

{% embed url="<https://www.youtube.com/watch?v=JtrQOzCmYjU>" %}

### Implementation and Scalability

* 🚀 Installation on a **Revolution Pi** involves system updates, MQTT setup, and configuring thin-edge.io with a **Cumulocity tenant ID**, demonstrating its adaptability to various edge devices.
* 🔄 **thin-edge.io** supports **remote software deployment** and **SSH passthrough**, allowing for secure access and updates to **Node-RED flows** on edge devices from anywhere.
* 📈 The framework is **easily scalable** for managing multiple devices in bulk, supporting configuration, firmware, and software management across large IoT deployments.

### IoT Data Management

* 📡 **Cumulocity** provides a range of **visualization widgets,** including alarms, graphs, and gauge charts, enabling customized dashboards for real-time IoT data monitoring and analysis.
* 👥 The platform supports **child device** creation, allowing for hierarchical data categorization and management in complex IoT ecosystems.

### Programming and Deployment

* OTee's **structure text editor** allows for efficient PLC programming using **IEC 61131-3 compliant language**, featuring **tag definition**, **variable creation**, **logic programming**, and **alarm creation**.
* The **onboarding process** for OTee involves adding a device, downloading an installer, running it on the edge device, and installing the **OTee agent** for real-time data exchange between the cloud and edge.

## Key notes:

{% embed url="<https://www.canva.com/design/DAGjTf2SPO4/X14NW6Pr82o53yhpbgRu8A/view?utlId=hc644062a04&utm_campaign=designshare&utm_content=DAGjTf2SPO4&utm_medium=link2&utm_source=uniquelinks>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# WAGO

Kindly check the sub-pages for more information

* [Predictive Maintenance and Data Analytics](/product-reviews/smart-platforms/wago/predictive-maintenance-and-data-analytics)
* [Remote App Deployment](/product-reviews/smart-platforms/wago/remote-app-deployment)


# Predictive Maintenance and Data Analytics

Introducing WAGO Library Analytics (from WAGO), a powerful tool that simplifies the integration of machine learning models into PLC programs for predictive maintenance and condition monitoring

## Out-of-the-box solution for Predictive Maintenance and Data Analytics <a href="#el_1719235576019_635" id="el_1719235576019_635"></a>

Are you looking for an out-of-the-box solution for **Predictive Maintenance and Data Analytics?** I'm thrilled to announce my latest video, where I focus on predictive maintenance for induction motors.

## Video Review

{% embed url="<https://www.youtube.com/watch?v=d2R_22WLghU>" %}

In this video, I introduce the WAGO Library Analytics (from WAGO). This powerful tool **simplifies the integration of machine learning models into PLC programs** for **predictive maintenance and condition monitoring.**\
\
By attaching simple sensors to your motor, such as vibration or temperature sensors, you can detect:

* Anomalies
* Drifts
* Forecast motor behavior

These metrics help in **preventing costly downtime** and ensuring smooth operation. Whether you're an engineer, a maintenance manager, or just passionate about automation and IIoT, join me as I demonstrate live data from my motor and explore how WAGO Library Analytics can transform your approach to maintenance.

Say goodbye to unexpected failures and hello to optimized performance!

## Key notes:

{% embed url="<https://www.canva.com/design/DAGxBNwRpJ8/z89OSW4L54XWvGaFyXvJwA/view?utlId=hf4c9d87466&utm_campaign=designshare&utm_content=DAGxBNwRpJ8&utm_medium=link2&utm_source=uniquelinks>" %}

#### WAGO is a registered trademark of WAGO Verwaltungsgesellschaft mbH. <a href="#el_1710502424804_440" id="el_1710502424804_440"></a>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Remote App Deployment

In this arti, I show step-by-step instructions on deploying a Node-RED app 📈 on WAGO's PFC200 8212 controller using WAGO's Solutions Platform 🚀. This app reads the IO status of the controller, and y

## WAGOs Solutions Platform

Here is my new video 🌐 on [WAGO](https://www.linkedin.com/company/wago/)'s solutions platform. I have been working on this platform for the last two months, and it is one of the easiest solutions from [WAGO](https://www.linkedin.com/company/wago/) for remote app development 🚀\
\
What amazes me 💡 the most about [WAGO](https://www.linkedin.com/company/wago/)'s Solution Platform is that:\
✅ The developers need to send only QR codes 📲 for app development\
✅ The electricians need their mobile phones 📱 with the WAGO app for device commissioning\
✅ You can containerize your app 📦 and create an edge stack file for deployment

## Video Review

{% embed url="<https://www.youtube.com/watch?v=wz1NnW4-0N4>" %}

In this video 📹, I show step-by-step instructions on deploying a Node-RED app on WAGO's PFC200 8212 controller using [WAGO](https://www.linkedin.com/company/wago/)'s Solutions Platform ✨.\
\
This app reads the IO status of the controller, and later, you will see data analytics on Grafana ([Grafana Labs](https://www.linkedin.com/company/grafana-labs/)) via MQTT 📊.

## Key notes:

{% embed url="<https://www.canva.com/design/DAF1W9QUiks/WNUNkslWbD6Efa53uneNKQ/view?utlId=h986a22b2c5&utm_campaign=designshare&utm_content=DAF1W9QUiks&utm_medium=link2&utm_source=uniquelinks>" %}

#### WAGO is a registered trademark of WAGO Verwaltungsgesellschaft mbH. <a href="#el_1710502424804_440" id="el_1710502424804_440"></a>

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Vibration sensor data on Augmented Reality

In this article, you will see an examples of using Augmented Reality for reading real-time data vibration sensor connected to Industrial motor

## Case 1: Reading the motor's vibration via AR <a href="#el_1690237193298_340" id="el_1690237193298_340"></a>

It's incredibly fun to integrate various technologies and create a use case. I am happy to share my tiny project, which allows me to visualize my motor's vibration and temperature measurements on SARA, i.e., SICK Augmented Reality Assistance.

* I am visualizing the sensor data in real-time from my vibration sensor MBP10, which is connected to the SIG350 IO-Link master from SICK Sensor Intelligence to read Temperature and Vibrations (V-RMS).
* The IO-Link master is connected to the Turck TX700D IOT Gateway via EtherCAT.

## Video example

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FKYVdtPfsJeiNmaFXQe5h%2FVibration%20Sensor%20Data%20On%20Augmented%20Reality.mp4?alt=media&token=e9405a08-b7f5-48f2-86e3-889272fd14e4>" %}

I am visualizing the sensor data in real-time from my vibration sensor [#MBP10](https://www.linkedin.com/search/results/all/?keywords=%23mbp10\&origin=HASH_TAG_FROM_FEED), which is connected to [#SIG350](https://www.linkedin.com/search/results/all/?keywords=%23sig350\&origin=HASH_TAG_FROM_FEED) IO-Link master from [SICK Sensor Intelligence](https://www.linkedin.com/company/sicksensorintelligence/) to read Temperature and Vibrations (V-RMS)📈. The [#IOLink](https://www.linkedin.com/search/results/all/?keywords=%23iolink\&origin=HASH_TAG_FROM_FEED) master is connected to the [Turck](https://www.linkedin.com/company/turck/) TX700D IOT Gateway via [#EtherCAT](https://www.linkedin.com/search/results/all/?keywords=%23ethercat\&origin=HASH_TAG_FROM_FEED)🌍.

## Case 2: Real-time data monitoring from Raspberry Pi

* I am visualizing the sensor data in real-time from my Raspberry Pi, which is docked with SensorHub to read Temperature, Humidity, and Air pressure.
* The Raspberry Pi is publishing the data to the SARA Server via MQTT.
* My mobile phone is connected via WiFi to the&#x20;

  SARA server and subscribing to the data.
* All the views and data points are defined in the SARA Editor running on the SARA server.

## Video example

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2FaqcJQAlF1FBhIHOcS0mE%2FAugmented%20Reality%20And%20Iiot.mp4?alt=media&token=499f4f4c-9b3d-4d43-9503-9894a0f2f79d>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# OEE made Easy with FlowFuse

This article how to make OEE dashboard of a simulated virtual factory using blueprints of FlowFuse

🚀 Super excited to share my **latest tech adventure** 😎: An **OEE Dashboard** powered by **FlowFuse Blueprints**! 🌟 And guess what 😮? It took me **just 45 minutes** to set it up with real-time data! ⏱️

## Video example

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLd2M9UNfMTnw9DjDdZJz%2Fuploads%2Fp355dKid6kNTdtX5elFU%2FOee%20Made%20Easy%20With%20Flowfuse.mp4?alt=media&token=bd832458-7039-4b08-81ef-e5c4689ad954>" %}

This dashboard is created using **ready-to-use blueprints from FlowFuse** 😍. I just customized the blueprint a bit to read real-time values from my virtual factory 🏭👩🏼‍🏭.\
\
🤖 I integrated my **Revolution Pi**, which communicates with FlowFuse’s server via **MQTT** and connects to the virtual factory via **OPC UA**\
\
Here's what my virtual factory sends to Revolution Pi via OPC UA:

* **🥇 Good and bad parts**
* **⏳ Run time**
* **⏸️ Stop time**

And the best part? I plug these values into the blueprint, and voilà! The OEE formula works its magic to **calculate OEE 🚀, Availability ✅, Performance 📈, and Quality.** ✨\
\
Watch closely 🧐, and you'll see the OEE changes as it tracks the good and bad parts being created. 📈 But wait, how did I crunch those OEE numbers? Let me break it down for you:

1. **Quality Calculation**: I'm analyzing the production counts (Good and Bad parts) from my factory, which the S7-1500 PLC communicates via OPC UA.&#x20;
2. Availability Check: I'm evaluating the total available time, system stop time, and run time to determine the optimal metric.
3. **Performance:** It is based on ideal production time, total parts created, and system run time to gauge the performance.

**And here's the magic equation:**

{% hint style="success" %}

### OEE = Performance x Availability x Quality. <a href="#el_1701686734310_369" id="el_1701686734310_369"></a>

{% endhint %}

## Resources <a href="#el_1705864237898_369" id="el_1705864237898_369"></a>

**Node-RED Flow:** You can use my Node-RED flow for reading from the virtual factory via OPC UA. It can also be run on your computer if you don't have an Edge device.

{% file src="/files/CJKGXXa2PXE9dZYNoCAX" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# SIGNL4- Get your PLC alerts on the mobile app

In this article, you will learn how to send PLC alerts directly to mobile app- SIGNL4

I'm super excited to share my next video 📹 on the SINGL4 app from 📱, which is a game-changer for efficient and reliable alerting 🚨. In this video,&#x20;

* I am reading the alerts from the shop floor and sharing them with the team via APIs.&#x20;
* Thanks to ctrlX AUTOMATION, I can use ctrlX CORE to host Node-RED, which bridges the S7-1200 PLC and the SIGNL4 server. &#x20;
* I created the digital twin on [Simumatik](https://www.codeandcompile.com/simumatik) to get the alarm signals.

## LIVE Demo

{% embed url="<https://www.youtube.com/watch?v=B4XL8aqFuRs>" %}

## **The information flow:**

1. The Simulated system is controlled via an S7-1200 PLC
2. Node-RED running on the ctrlX CORE is reading alerts from the S7-1200 via S7 connection.
3. Node-RED processes the alerts and sends them to the SIGNL4 server via API.
4. SIGNL4 distributes the alarms to the team, ensuring important notifications reach the right people at the right time.&#x20;
5. The user brings the system to maintenance mode via the SIGNL4 app

{% hint style="success" %}
✅ Try SIGNL4 for 30 30-day free trial version to test drive the alert management platform. Head over to their website 👉<https://www.signl4.com>
{% endhint %}

## Key notes:

{% embed url="<https://www.canva.com/design/DAFkNu_VJIA/LIhkqsdokgvKCa_iw6ETSw/view?utlId=hac3b2f1ba9&utm_campaign=designshare&utm_content=DAFkNu_VJIA&utm_medium=link2&utm_source=uniquelinks>" %}

## ♥️ 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: <rajvir@codeandcompile.com> or drop me a message on [LinkedIn](https://www.linkedin.com/in/singhrajvir/)


# Industrial Control

Resource page for Industrial Control section of our courses

Industrial controls are systems that regulate and manage the operation of industrial machinery and processes. They include programmable logic controllers (PLCs), human-machine interfaces (HMIs), and other devices that monitor and control variables like temperature, pressure, and flow. Industrial controls improve process efficiency, productivity, and safety, and are used in various industries including manufacturing, energy, and transportation.

{% file src="/files/4YMVKapdeUJDN6dPIJh7" %}


# Digital Twin

Stop twinning around

A digital twin is a virtual replica of a physical object or system, created using real-time data and simulations. It allows for analysis, monitoring, and optimization of the physical system's performance, making it useful in various industries like manufacturing, healthcare, and transportation.

The following are the topics connected to digital Twin:

1. [Simumatik](/factory-automation/digital-twin/simumatik)
2. [FACTORY IO](/factory-automation/digital-twin/factory-io)


# FACTORY IO

💻 In this page, you will find all the available resources for the course Factory Automation using PLC.

### ⚙ Download the software

The software used in this course is FACTORY I/O which you can download from the link here:[Hardware and Software](/resources/hardware-and-software). The software is available for 30 days trial period and if you want to extend the license, you can order here for as low as 15€/month.

{% embed url="<https://codeandcompile.com/factory-io>" %}
Weblink to order your software license
{% endembed %}

### 💻 Online Course

If you are not enrolled in the Factory Automation using PLC course then join at&#x20;

{% embed url="<https://codeandcompile.com/course/factory-automation>" %}
**E-Learning course**
{% endembed %}

### ✅ FACTORY IO Scene and CONTROL IO program

In the following page, you will find the solutions for the tasks which are solved in the E-Learning course. In the solution, you will find the FACTORY IO scene and CONTROL IO program. You must open them together to start the simulation

[Tasks and Solutions](/factory-automation/digital-twin/factory-io/tasks-and-solutions)

FACTORY IO Scenes

{% hint style="info" %}
💡 Feel free to revert back to <compiletocode@gmail.com> if you find any bug in the download link or document
{% endhint %}

### More information

Check the online documentation of FACTORY IO at this page [Books and Guides](/resources/books-and-guides)where you will learn how to integrate various PLCs or SoftPLCs with FACTORY IO.


# Tasks and Solutions

In this page, you will find solutions for some of the pre-build FACTORY I/O scene. Feel free to download, use or modify the solutions.

### Software platform: FACTORY I/O

{% hint style="success" %}
Download link for the solution is given at the end of the page. Kindly scroll down
{% endhint %}

### Task 1: From A to B

In this solution, you will learn how to use contact logic instructions for moving the box from A to B.

![Pre-built scene in FACTORY I/O](/files/Isie4oMDrTt3WmFvHSUz)

### Task 2: From A to B (SET/RST)

In this solution, you will make the same logic using SET and RESET instructions

<figure><img src="/files/8Rw5d6PbPsB4cd6yYI5F" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 3: Filling Tank (Timers)

In this solution, you will learn how to use timers for filling and draining the tank

<figure><img src="/files/OdDxc8tr0hznylfAujF5" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 4: Queue of Items (Counter)

In this solution, you will learn how to use counter for counting the objects on the conveyor

<figure><img src="/files/NWE3SknLcGL9aZ647dOX" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 5: Assembler

In this solution, you will learn how to make sequence logic to assemble the upper and lower part using digital IOs

<figure><img src="/files/zmZ9oqPPx74tm4ASaPnh" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 6: Assembler analog

In this solution, you will learn how to make sequence logic to assemble the upper and lower part using analog IOs

<figure><img src="/files/zmZ9oqPPx74tm4ASaPnh" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 7: Buffer Station

In this solution, you will learn how to make buffer logic for the conveyor system

<figure><img src="/files/sIqivWorVRKutSBjUbE5" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 11: Basic PID explanation

In this solution, you will learn the basics of PID algorithm using analog sensor and analog conveyor

<figure><img src="/files/0XiSyXuKKPcqir7hpRB2" alt=""><figcaption><p>Customzed scene</p></figcaption></figure>

### Task 12: PID Level Control

In this solution, you will learn how to implement PID logic to the tank level system to control the tank liquid

<figure><img src="/files/wznosqaKL9niZ08dwZWg" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 14: Sorting by height (Basic)

In this solution, you will learn how to sort the object based on height

<figure><img src="/files/zwTgXcEyMoTr7dl8JmoS" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 16: Sorting by weight

In this solution, you will learn how to sort the object based on weight

<figure><img src="/files/6piAQT5tbazAGyW9b2Tk" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Task 19: Production line

In this solution, you will learn how to make production flow system using conveyors and robot working together

<figure><img src="/files/xXQleJmQOpAibiXYZjU1" alt=""><figcaption><p>Pre-built scene in FACTORY I/O</p></figcaption></figure>

### Download all solutions

Download all the solutions using the file below. Kindly use [WinRAR ](https://www.win-rar.com/start.html?\&L=0)to extract the files from the file

{% file src="/files/uRrk1rPv3rnjArtTpE6F" %}

### Building Conveyor line

Solutions are given in the file below

{% file src="/files/FKJVLRcoln7K6Ukfq8AS" %}


# FACTORY IO Scene

In this page, you will find the FACTORY IO Scene used in various courses

### 📊 Node-RED made Easy Course

Course link: <https://codeandcompile.com/course/node-red-made-easy>

{% file src="/files/eUy6SLIsIna9auGOoogn" %}

### Learn S7-1200 PLC and HMI from Scratch (Basic)

Course link: <https://codeandcompile.com/course/learn-siemens-s7-1200-and-hmi-basic>

{% file src="/files/v8B5jUwqzD9mWuOyiT5j" %}

### Micro850 PLC and IIoT Course

Course link: <https://codeandcompile.com/course/micro850-plc>

{% file src="/files/9LbhfKwqEEtruGNRM9YI" %}


# Simumatik

Get free access to the learning videos explaining how to build a virtual control system and control it using PLC

## Introduction

Code and Compile introduces you to an excellent cloud-based emulation platform, [Simumatik](https://www.codeandcompile.com/simumatik), enabling you to bring your ideas to life and create intelligent Mechatronics systems using PLC, Conveyors, sensors, or IIoT devices.

#### **In these videos, you will learn:**

1. How to develop **virtual mechatronics systems**
2. How to interface the system with **Codesys and Siemens S7-1200** to control the system using your algorithm
3. How to interface the system with an **MQTT Broker via Node-RED** to connect to the **IIoT world**

{% content-ref url="/spaces/Ld2M9UNfMTnw9DjDdZJz/pages/uigMdSDuR1nJd3bzsMCW" %}
[01: Introduction to Simumatik](/factory-automation/digital-twin/simumatik/01-introduction-to-simumatik)
{% endcontent-ref %}

{% content-ref url="/spaces/Ld2M9UNfMTnw9DjDdZJz/pages/tukxkd50kW7yAktGQWJ8" %}
[02: Conveyor ON-OFF control](/factory-automation/digital-twin/simumatik/02-conveyor-on-off-control)
{% endcontent-ref %}

{% content-ref url="/spaces/Ld2M9UNfMTnw9DjDdZJz/pages/PpVoeBEs81G0uPKfmONl" %}
[03: Conveyor direction control](/factory-automation/digital-twin/simumatik/03-conveyor-direction-control)
{% endcontent-ref %}

{% content-ref url="/spaces/Ld2M9UNfMTnw9DjDdZJz/pages/ZYGCKF0XP3RW8ZgaG7F1" %}
[04: Motor Control with Codesys](/factory-automation/digital-twin/simumatik/04-motor-control-with-codesys)
{% endcontent-ref %}

{% content-ref url="/spaces/Ld2M9UNfMTnw9DjDdZJz/pages/FbKaFuKsQ8mUpsRjhB3p" %}
[05: Electro-Pneumatics with S7-1200 PLC](/factory-automation/digital-twin/simumatik/05-electro-pneumatics-with-s7-1200-plc)
{% endcontent-ref %}

{% content-ref url="/spaces/Ld2M9UNfMTnw9DjDdZJz/pages/5vC4gwXJFHCT3iUQAKg6" %}
[06: Control IoT Device with MQTT](/factory-automation/digital-twin/simumatik/06-control-iot-device-with-mqtt)
{% endcontent-ref %}

## Features

* Reduce commissioning **time and cost**
* **Develop and test PLC and Robot logic** in a digitized physical lab
* Train operators in a safe environment from **anywhere and anytime** in a web based environment
* Connect to **third-party hardware & software** via various drivers
* Create your own components and **collaborate** in real-time

## Free courses

Check out the [Simumatik Academy](https://academy.simumatik.com/)  and [Code and Compile free courses](https://www.codeandcompile.com/simumatik)  to learn more about SIMUMATIK

## 🛒 [Buy License](https://www.codeandcompile.com/simumatik)


# 01: Introduction to Simumatik

⏲️ Duration 2:57

Learn what you can do with Simumatik. Does it fit your professional or educational needs?

{% embed url="<https://youtu.be/tpPuAEpuEVg>" %}


# 02: Conveyor ON-OFF control

⏲️ Duration 18:59

Learn how to use the Simumatik platform to build your own virtual system starting from scratch.

{% embed url="<https://youtu.be/O2WX6suYDtg>" %}


# 03: Conveyor direction control

⏲️ Duration 10:41

Learn how to control the operation and direction of an AC motor using customized panel.

{% embed url="<https://youtu.be/sHcDszBtGP4>" %}


# 04: Motor Control with Codesys

⏲️ Duration 20:05

Learn how to control the operation and direction of AC motor using Codesys ladder logic. Interfacing of Simumatik and Codesys is achieved via OPC UA connection

{% embed url="<https://youtu.be/YHBSx-luAHY>" %}


# 05: Electro-Pneumatics with S7-1200 PLC

⏲️ Duration 18:24

In this video, you will learn how to simulate a Pneumatic circuit and furthermore how to control it using S7-1200 PLC using the Simumatik OPC UA driver.

{% embed url="<https://youtu.be/TU-BwvvMmb4>" %}


# 06: Control IoT Device with MQTT

⏲️ Duration 11:25

Learn how to control the IoT devices in Simumatik via MQTT. In this example, Node-RED is used as MQTT Broker and the client to control and read the status of various IoT devices in Simumatik

{% embed url="<https://youtu.be/KAobD31WR2A>" %}


# Resources

**The following are the resources that are used in the course videos**

<table><thead><tr><th>Name</th><th width="150">Type<select><option value="6bceb737eff84fe69ac577b9d879ab4b" label="pdf" color="blue"></option><option value="2144067bbfa849098d85a6f522bc954f" label="3D" color="blue"></option><option value="b61cfd964a4942f19468c0e0f7f13816" label="others" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Video 03: Conveyor direction Control</td><td><span data-option="6bceb737eff84fe69ac577b9d879ab4b">pdf</span></td><td><a href="/files/5rWc8IVFIljQBgpw8GSE">/files/5rWc8IVFIljQBgpw8GSE</a></td></tr><tr><td>Video 04: Motor control with Codesys</td><td><span data-option="6bceb737eff84fe69ac577b9d879ab4b">pdf</span></td><td><a href="/files/eKUTycKlLlcpjr8oNvHq">/files/eKUTycKlLlcpjr8oNvHq</a></td></tr><tr><td>Video 05: Electro-Pneumatics with S7-1200 PLC</td><td><span data-option="6bceb737eff84fe69ac577b9d879ab4b">pdf</span></td><td><a href="/files/CdjdwB7okv7EYY1n4lM9">/files/CdjdwB7okv7EYY1n4lM9</a></td></tr></tbody></table>

## Free courses

Check out our academy for **free courses** to scale up your experience with **Simumatik**

* 👩‍💻 [Old Academy](https://academy.simumatik.com)
* 🌍 [New Academy](https://newacademy.simumatik.com)

*Note: The content from the old academy is being transferred to the new academy.*

### Free sign up for Simumatik 30 days trial&#x20;

{% embed url="<https://bit.ly/3xxnTTw>" %}
Sign up for free
{% endembed %}


# PLC

In this page, you will find PLC software and exercises.

A PLC, or Programmable Logic Controller, is a device that can control industrial machinery and processes. It's like the brain of the system, making sure everything works together smoothly. It's so reliable, it's like having a robot that never complains, takes coffee breaks, or goes on vacation - unless, of course, there's a power outage.

{% content-ref url="/pages/8tCvCUHBiuUsiwhNbZtP" %}
[Allen Bradley](/factory-automation/plc/allen-bradley)
{% endcontent-ref %}

{% content-ref url="/pages/y8GBjMBeznunNBKhfksA" %}
[Delta Electronics](/factory-automation/plc/delta-electronics)
{% endcontent-ref %}

{% content-ref url="/pages/fyzU72flo2XYlAFJsxc8" %}
[Omron](/factory-automation/plc/omron)
{% endcontent-ref %}

{% content-ref url="/pages/QgxyQNBz7rteZgTqGjRY" %}
[PLCnext](/factory-automation/plc/plcnext)
{% endcontent-ref %}

{% content-ref url="/pages/TZReHgDmw0xyaVvaz7qu" %}
[Siemens](/factory-automation/plc/siemens)
{% endcontent-ref %}

{% content-ref url="/pages/UC4gtJ2eyBSLtgGpeLbR" %}
[Codesys](/factory-automation/plc/codesys)
{% endcontent-ref %}


# Allen Bradley

In this page you will find resources related to Allen Bradley course modules

The following PLC resources are available in this page:

* [Micro850 PLC](/factory-automation/plc/allen-bradley/micro850-plc)
* [Micrologix 1000 PLC](/factory-automation/plc/allen-bradley/micrologix-1000-plc)
* [Micrologix 1400 PLC](/factory-automation/plc/allen-bradley/micrologix-1400-plc)


# Micro850 PLC

In this page you will find resources related to Micro850 PLC

### Online Course

On this page, you will find all the available resources for the PLC Micro850 Lessons which is available in the following course:&#x20;

{% embed url="<https://codeandcompile.com/course/allen-bradley-course-module-plc-scada-ac-drives>" %}

### Lesson 1- Introduction to Micro850 PLC

In this video, you will learn about Micro850 PLC from Allen Bradley. Access the full course with 30+ videos on our E-Learning Platform [www.codeandcompile.com](http://www.codeandcompile.com) or direclty by visiting this link: <https://codeandcompile.com/course/allen-bradley-course-module-plc-scada-ac-drives>

{% embed url="<https://www.youtube.com/watch?v=tVuEqOSLhSQ&ab_channel=RajvirSingh>" %}

### PLC Software

The programming software which is required to program Micro850 PLC is **Connected Component Workbench**. The link to download this software can be found at [Hardware and Software](/resources/hardware-and-software)

### :books: Resources

The following are the PLC Program used in the course. You can use it as a reference.

<table><thead><tr><th>Title</th><th>Type<select><option value="463241c7473a47c88856694c56f19a15" label="ccw file" color="blue"></option><option value="1bc81b2949ac47ce927a24ff4337f4e4" label="factory io file" color="blue"></option><option value="cb8da7e0fbb84683a8d42f2323ac51c2" label="pdf" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Introduction to the Micro850 PLC</td><td><span data-option="cb8da7e0fbb84683a8d42f2323ac51c2">pdf</span></td><td><a href="/files/oKtHV4OWXYDemyQV61UH">/files/oKtHV4OWXYDemyQV61UH</a></td></tr><tr><td>Simple Box Sorting version 1</td><td><span data-option="463241c7473a47c88856694c56f19a15">ccw file</span></td><td><a href="/files/cTVcHhI8nb2wLwQzYynV">/files/cTVcHhI8nb2wLwQzYynV</a></td></tr><tr><td>Simple Box Sorting v2</td><td><span data-option="463241c7473a47c88856694c56f19a15">ccw file</span></td><td><a href="/files/8FXbk3LQy88qChLfhB00">/files/8FXbk3LQy88qChLfhB00</a></td></tr><tr><td>Factory IO Environment for Simple Box Sorting</td><td><span data-option="1bc81b2949ac47ce927a24ff4337f4e4">factory io file</span></td><td><a href="/files/VSDpMOewYbxsOiV7tshx">/files/VSDpMOewYbxsOiV7tshx</a></td></tr></tbody></table>

### ✅ Exercises to practice:

{% content-ref url="/pages/fBdyXaf1cF1HSbkzsNdy" %}
[PLC Exercises - Part 1](/factory-automation/plc/allen-bradley/micro850-plc/plc-exercises-part-1)
{% endcontent-ref %}

{% content-ref url="/pages/D8Om8gHEJcD4OdEaD2nD" %}
[PLC Exercises - Part 2](/factory-automation/plc/allen-bradley/micro850-plc/plc-exercises-part-2)
{% endcontent-ref %}

{% hint style="success" %}
The **solutions** **in Ladder Diagram, FBD and ST** are available in the course **Micro850 PLC**: <https://codeandcompile.com/course/micro850-plc>&#x20;
{% endhint %}

### More information

Learn more about Micro850 PLC at this page [Books and Guides](/resources/books-and-guides)


# PLC Exercises - Part 1

Practice your PLC Programming for Ladder Diagram, FBD and Structured Text Programming

{% hint style="success" %}
The **solutions** **in Ladder Diagram, FBD and ST** are available in the course **Micro850 PLC**: <https://codeandcompile.com/course/micro850-plc>&#x20;
{% endhint %}

**Solve the following exercises in the following programming languages:**\
\- Ladder Diagram\
\- FBD (Funcitonal Block Diagram)\
\- ST (Structured Text)

{% hint style="warning" %}
In the following exercises, consider declaring the variables as follows.
{% endhint %}

<table><thead><tr><th width="157">Variable type</th><th width="121">Data type</th><th width="233">Variable declaration</th><th>Remarks</th></tr></thead><tbody><tr><td>Input, Output</td><td>Bool</td><td>xStart, xStop, xReset, xInput, xSensor, xInductiveSensor, xMotor, xSolenoid etc.</td><td>The first alphabet defines the datatye followed by variable name</td></tr><tr><td>Value</td><td>Int or Int16</td><td>iCount, iLevel, iSpeed etc.</td><td></td></tr><tr><td>Value</td><td>DInt or Int32</td><td>diCount, diLevel, diOrderID etc.</td><td></td></tr><tr><td>Value</td><td>Real</td><td>rSpeed, rLevel, rHeight etc.</td><td></td></tr><tr><td>Name</td><td>String</td><td>sID, sRecipe, sPassword etc.</td><td></td></tr><tr><td>Parameter</td><td>Time</td><td>tDelay, tTimeout etc.</td><td></td></tr></tbody></table>

## Section 1 - Series & Parallel logics

1. Write a program when xStart is TRUE, xMotor should be TRUE, and when xStart is False, xMotor should be FALSE.
2. Write a program to fulfill the following boolean table:

|          xStartA :BOOL (Input)         |          xStartB :BOOL (Input)         |        xOutputX : BOOL (Output)        |
| :------------------------------------: | :------------------------------------: | :------------------------------------: |
|  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |
|  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> |
| <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |
| <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> |

3. Write a program to fulfill the following boolean table:

|          xStartA :BOOL (Input)         |          xStartB :BOOL (Input)         |        xOutputX : BOOL (Output)        |
| :------------------------------------: | :------------------------------------: | :------------------------------------: |
|  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |
|  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> |
| <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> |
| <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> |

4. Write a program to fulfill the following boolean table:

|          xStartA :BOOL (Input)         |        xOutputX : BOOL (Output)        |
| :------------------------------------: | :------------------------------------: |
|  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> |
| <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> |

5. Write a program to fulfill the following boolean table:

<table><thead><tr><th align="center">xStartA :BOOL (Input)</th><th width="251.33333333333331" align="center">xOutputX :BOOL (OUTPUT)</th><th align="center">xOutputY : BOOL (Output)</th></tr></thead><tbody><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr></tbody></table>

6. Write a program to fulfill the following boolean table:

<table><thead><tr><th align="center">xStartA :BOOL (Input)</th><th width="246.33333333333331" align="center">xOutputX :BOOL (OUTPUT)</th><th align="center">xOutputY : BOOL (Output)</th></tr></thead><tbody><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr></tbody></table>

7. Write a program to fulfill the following boolean table:

<table><thead><tr><th align="center">xStartA :BOOL (Input)</th><th width="246.33333333333331" align="center">xStartB :BOOL (Input)</th><th align="center">xOutputY : BOOL (Output)</th></tr></thead><tbody><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr></tbody></table>

## Section 2 - Latching and Interlocking logics using contacts

1. Write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched. \
   In this case, consider xStart and xStop as NO Push Button.
2. Write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched. \
   In this case, consider xStart and xStop as NC Push Button.
3. Write a program to interlock xSolenoidA (Output) and xSolenoidB (output). \
   \- When xStartA (Input) is pressed, xSolenoidA (output) should be latched, and xSolenoidB should be unlatched\
   \- When xStartB (Input) is pressed, xSolenoidB (output) should be latched, and xSolenoidA should be unlatched\
   \- When xStop (Input) is pressed or when xStart A and xStartB both are pressed , both solenoids should be unlatched\
   Consider xStartA, xStartB as NO push button, and xStop as NC Push Button.

## Section 3 -  RS and SR flip-flops

1. Using RS flipflop write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched. \
   In this case, consider xStart as NO push button and xStop as NC Push Button.
2. Using SR flipflop write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched. \
   In this case, consider xStart as NO push button and xStop as NC Push Button.
3. Realize the difference in operations when both the inputs xStart and xStop are TRUE. Which type of flipflop should be used ideally in this situation?

## Section 4- Use of Timers

{% hint style="info" %}
TON: On-delay timer; TOF: Off-delay timer; TONOFF: On Off delay Timer
{% endhint %}

1. Write a program such that when xStart (Input) is TRUE, xMotor (Output) gets TRUE after a delay of 5 secs. When xStart is FALSE, xMotor should be FALSE.
2. Write a program when xStart (Input) is TRUE, xMotorA (Output) gets TRUE after 3 seconds delay, and then after a delay of 3 more seconds,  xMotorB (Output) should get TRUE & after a delay of 3 more seconds, xMotorC (Output) should get TRUE.&#x20;
3. Write a program if xStart (Input) is TRUE xMotor (Output) is TRUE for 10 seconds, then gets FALSE. Consider xStart as Push button NO
4. Write a program such that:\
   \- xStart (Input) latches xMotorA (Output)\
   \- After a delay of 10 seconds, xMotorB (Output) latches\
   \- xStop (Input) unlatches xMotorA\
   \- After a delay of 10 seconds, xMotorB should get unlatched.\
   Consider xStart as Push button NO and xStop as Push button NC
5. Write a program in which xMotor (Output) latches only when xStartB is TRUE within 10 seconds just after the xStartA gets TRUE. Otherwise, if xStartB is TRUE after 10 seconds, xMotor should not be latched. xMotor should unlatch using xStop\
   Consider xStartA as Toggle Sw and xStartB as Push button NO and xStop as Push button NC<br>

## Section 5- Use of Timers with Comparators&#x20;

{% hint style="info" %}
EQ: Equal\
NE: Not equal\
LT: Less than\
LE: Less than or equals\
GT: Greater than\
GE: Greater or equals &#x20;
{% endhint %}

1. Use xStart (NO Push button) to actuate xMotor in the following sequence:\
   xMotor is TRUE for 2 seconds, then FALSE for 2 seconds, then TRUE for 3 seconds, then FALSE. The cycle should repeat when xStop (NC Push button) is pressed.
2. Use xStartA (Input) to blink xLamp (Output) such that the On-time is 2 seconds and Off-time is 3 seconds.
3. Write a program such that:\
   \- When xStartA (Input) is TRUE and xStartB (Input) is FALSE, xLampA (Output) and xLampB should blink continuously with a delay of 1 second.\
   \- When xStartB (Input) is TRUE and xStartA (Input) is FALSE, xLampA (Output) and xLampB should blink continuously with a delay of 2 seconds.\
   \- In other situations, the lamps should not be ON
4. Write a simple traffic light program to fulfill the following conditions. The cycle should start with xStart. The Timer should reset, and the cycle should repeat when the time is above 25 seconds. The cycle should stop and all outputs should be FALSE when xStart is FALSE .&#x20;

<table><thead><tr><th align="center">Time (in seconds)</th><th width="163" align="center">xRed (Output)</th><th width="175" align="center">xOrange (Output)</th><th align="center">xGreen (Output)</th></tr></thead><tbody><tr><td align="center">0 ~ 10</td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center">11 ~ 12</td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center">12 ~ 23 </td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center">24 ~ 25</td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr></tbody></table>

## Section 6- Use of Counters with Comparators&#x20;

{% hint style="info" %}
CTU: Up Counter\
CTD: Down Counter\
CTUD: Up-Down Counter
{% endhint %}

1. Write a program such that when xStart is pressed three times, xOutput should get TRUE. And when xReset is TRUE once, the xOutput should be FALSE, and the counter should RESET.&#x20;
2. Write a program to fulfill the following conditions:\
   \- When xStart is pressed once -xOutputA should be TRUE, xOutputB and xOutputC should be FALSE\
   \- When xStart is pressed again -xOutputB should be TRUE, xOutputA and xOutputC should be FALSE\
   \- When xStart is pressed again -xOutputC should be TRUE, xOutputA and xOutputB should be FALSE\
   \- When xStart is pressed again - all the outputs should be FALSE, and the cycle should repeat itself

## Section 7- Use of variables with Math Operators &#x20;

{% hint style="danger" %}
The following exercises are only possible with **Ladder diagram or Structured Text** as some commands with FBD does not support EN/ENO which are required for some operations.
{% endhint %}

{% hint style="info" %}
+: Addition\
\-: Subtraction\
\*: Multiplication\
/: Division\
MOV: Move
{% endhint %}

1. Write a program to fulfill the following conditions:\
   \- xStart (NO Push Button) should latch the xLamp (output) after cetain delay.  \
   \- xStop (NC Push Button) should unlatch the bLamp\
   \- Use xTimeA (Input) to set the delay time to 10 seconds.\
   \- Use xTimeB (Input) to set the delay time to 5 seconds.
2. Write the same program as the above but instead of moving the constant time of 5 and 10 seconds. Use xInc (Input) to increment the time by 100ms and xDec (Input) to decrement the time by 100ms.&#x20;
3. Add a program to the solution of Exercise 7.2. Set the default preset time of Timer to be 2 seconds and limit the minimum and maximum time to 1 second and 3 seconds, respectively.&#x20;

{% hint style="success" %}
The **solutions** **in Ladder Diagram, FBD and ST** are available in the course **Micro850 PLC**: <https://codeandcompile.com/course/micro850-plc>&#x20;
{% endhint %}


# PLC Exercises - Part 2

under construction 🚧👷‍♂️


# Micrologix 1000 PLC

In this page you will find resources related to Micro1000 PLC

### Online Course

On this page, you will find all the available resources for the Micrologix 1000 PLC Lessons which is available in the following course:&#x20;

{% embed url="<https://codeandcompile.com/course/allen-bradley-course-module-plc-scada-ac-drives>" %}

### PLC Software

The programming software which is required to program Micrologix 1000 PLC is **RsLogix 500**. The link to download this software can be found at [Hardware and Software](/resources/hardware-and-software)

### Resources

The following are the various resources that are used in the web series These are extremely helpful as a reference guide.

<table><thead><tr><th width="185.45756746186936">Name</th><th width="150">Type<select><option value="494520ccb75949cca7a92310555f85de" label="pdf" color="blue"></option><option value="8fdd12a9343e43398eb2afe07e1a9a94" label="pptx" color="blue"></option><option value="e22ca6a79a304dcd98e420bad185843f" label="rar" color="blue"></option><option value="dc9d7bc629bb452f920d9d9460f1d826" label="TIA Portal file" color="blue"></option><option value="af32221477cc4bf3b1d904ca4af98977" label="txt" color="blue"></option><option value="60c16abee0bb4a2cbcde86a8e4e68038" label="others" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Analog cards</td><td><span data-option="494520ccb75949cca7a92310555f85de">pdf</span></td><td><a href="/files/TNiEdJhn7ynpFLULdd4M">/files/TNiEdJhn7ynpFLULdd4M</a></td></tr></tbody></table>

### More information

Learn more about Micrologix 1000 PLC at this page [Books and Guides](/resources/books-and-guides)


# Micrologix 1400 PLC

In this page you will find resources related to Micro1000 PLC

### Online Course

On this page, you will find all the available resources for the Micrologix 1400 PLC Lessons which is available in the following course:&#x20;

{% embed url="<https://codeandcompile.com/course/allen-bradley-course-module-plc-scada-ac-drives>" %}

### PLC Software

The programming software which is required to program Micrologix 1400 PLC is **RsLogix 500**. The link to download this software can be found at [Hardware and Software](/resources/hardware-and-software)

### More information

Learn more about Micrologix 1400 PLC at this page [Books and Guides](/resources/books-and-guides)


# Delta Electronics

### The following PLC resources are available:

[DVP 14SS2](/factory-automation/plc/delta-electronics/dvp-14ss2)

[DVP 12SE](/factory-automation/plc/delta-electronics/dvp-12se)

[DVP 10SX](/factory-automation/plc/delta-electronics/dvp-10sx)

## PLC Exercises

[PLC Exercises 1](/factory-automation/plc/delta-electronics/plc-exercises-1)

{% hint style="info" %}
The solutions are not available but if you would like to volunteer, feel free to solve the exercises and share solutions in Ladder, FBD and ST programming language
{% endhint %}

## PLC Programs

{% file src="/files/dOLKAVQnGdV0CUN4ubMP" %}


# DVP 14SS2

PLC with Digital IOs along with Rs232 and Rs485 communication port

### Where you can use DVP 14SS2 PLC?

In the application where you just need digital logic control without Ethernet communication. This PLC has 8 inputs and 4 outputs with possibility to extend IOs. Learn more about this PLC [here](https://www.deltaww.com/en-us/products/PLC-Programmable-Logic-Controllers/253).

### Resources

The following are the various resources that are used in the web series These are extremely helpful as a reference guide.

<table><thead><tr><th width="185.45756746186936">Name</th><th width="150">Type<select><option value="494520ccb75949cca7a92310555f85de" label="pdf" color="blue"></option><option value="8fdd12a9343e43398eb2afe07e1a9a94" label="pptx" color="blue"></option><option value="e22ca6a79a304dcd98e420bad185843f" label="rar" color="blue"></option><option value="dc9d7bc629bb452f920d9d9460f1d826" label="TIA Portal file" color="blue"></option><option value="af32221477cc4bf3b1d904ca4af98977" label="txt" color="blue"></option><option value="60c16abee0bb4a2cbcde86a8e4e68038" label="others" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>PLC Exercise sheet</td><td><span data-option="494520ccb75949cca7a92310555f85de">pdf</span></td><td></td></tr></tbody></table>

### PLC Software

Download the Delta PLC software directly from the Delta website. Check out the software links here [Hardware and Software](/resources/hardware-and-software)

### More information

Learn more about DVP 14SS2 PLC at this page [Books and Guides](/resources/books-and-guides)


# DVP 12SE

PLC with Digital IOs along with Ethernet, Rs232 and Rs485 communication port

### Where you can use DVP 12SE PLC?

In the application where you just need digital logic control with Ethernet communication. Using Ethernet communication, it is relatively easy to link it to SCADA, Node-RED or any other hardware/software that supports MODBUC TCP/IP.&#x20;

This PLC has 8 inputs and 4 outputs with possibility to extend IOs. Learn more about this PLC [here](https://www.deltaww.com/en-us/products/PLC-Programmable-Logic-Controllers/253).

### Online Course

On this page, you will find all the available resources for the course Delta Automation Course Module- PLC, HMI and Drives

{% embed url="<https://codeandcompile.com/course/delta-automation-course-module-plc-hmi-and-drives>" %}

### Course resources

<table><thead><tr><th>Title</th><th width="117.33333333333331">File type<select><option value="c4fdabdaab6b4ff58f6aee719cc88992" label="pdf" color="blue"></option><option value="a84ead6946274b2b9af56d11d63fc5c7" label="zip" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Introduction to the PLC</td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/TeG04r3IyCpic8dJYUsh">/files/TeG04r3IyCpic8dJYUsh</a></td></tr><tr><td>PLC Wiring</td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/repZzwtqytHueGHjuPA1">/files/repZzwtqytHueGHjuPA1</a></td></tr><tr><td>PLC Commands- AND, OR, XOR and INV</td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/LwcXGEkBs0nWMbyl1hjO">/files/LwcXGEkBs0nWMbyl1hjO</a></td></tr><tr><td>PLC Commands- SET, RESET, PLS and PLF</td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/oqn2EbssQ20eFSDqVWXJ">/files/oqn2EbssQ20eFSDqVWXJ</a></td></tr><tr><td>PLC Hand written notes</td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/lqsalEkkr9s3hnoigo1U">/files/lqsalEkkr9s3hnoigo1U</a></td></tr><tr><td>Interfacing with <a href="/pages/PqryHWL6Zg98O3NZJ4Gm">FACTORY IO</a></td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/LpjXsXPTgPA5uTd7bixA">/files/LpjXsXPTgPA5uTd7bixA</a></td></tr><tr><td>Interfacing with Kepware and Excel</td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/rIrX8f8Rk2cK93o4m6N0">/files/rIrX8f8Rk2cK93o4m6N0</a></td></tr><tr><td>Interfacing with <a href="/pages/xvmo44bNMJxh9EGArMch">EasyBuilder Pro (Virtual HMI)</a></td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/gjs0mqxDWQOJD7nUisnZ">/files/gjs0mqxDWQOJD7nUisnZ</a></td></tr><tr><td>Interfacing with MODBUS POLL</td><td><span data-option="c4fdabdaab6b4ff58f6aee719cc88992">pdf</span></td><td><a href="/files/eo4XLlRUz48RSYdXysLs">/files/eo4XLlRUz48RSYdXysLs</a></td></tr><tr><td>Palletizer Logic (PLC and HMI)</td><td><span data-option="a84ead6946274b2b9af56d11d63fc5c7">zip</span></td><td><a href="/files/VBvovQoxiOz1Olw5yByc">/files/VBvovQoxiOz1Olw5yByc</a></td></tr></tbody></table>

### PLC Software

Download the Delta PLC software directly from the Delta website. Check out the software links here [Hardware and Software](/resources/hardware-and-software)

### More information

Learn more about DVP 12SE PLC at this page [Books and Guides](/resources/books-and-guides)


# DVP 10SX

PLC with Digital and Analog IOs along with Rs232 and Rs485 communication port

### Where you can use DVP 10SX PLC?

In the application where you need digital and analog logic control. This PLC has inbuilt analog input and output. Learn more about this PLC [here](https://www.deltaww.com/en-us/products/PLC-Programmable-Logic-Controllers/158).

### Online Course

On this page, you will find all the available resources for the course Delta Automation Course Module- PLC, HMI and Drives

{% embed url="<https://codeandcompile.com/course/delta-automation-course-module-plc-hmi-and-drives>" %}

### Analog Input and Output notes (Hand written)

{% file src="/files/UiYnR7lcb04UbpIbw2i0" %}
Analog input notes
{% endfile %}

{% file src="/files/EslS6xb1FibV4MAkF2bc" %}
Analog output notes
{% endfile %}

### PLC Software

Download the Delta PLC software directly from the Delta website. Check out the software links here [Hardware and Software](/resources/hardware-and-software)

### More information

Learn more about DVP 10SX PLC at this page [Books and Guides](/resources/books-and-guides)


# PLC Exercises 1

Practice your PLC Programming skills using these exercises

{% hint style="danger" %}
If you receive error while executing your logic, it could be because you cannot normally actuate inputs (X0, X1, X2 and so on..) in the simulator so in this case, kindly practice your exercise using memory bits (M0, M1, M2 and so on..) instead of inputs (X0, X1, X2 and so on..)
{% endhint %}

{% hint style="success" %}
If you are using AHCPU, you should use input bits as X0.0, X0.1 instead of X0, X1 and outputs as Y0.0, Y0.1 instead of Y0, Y1 and so on.&#x20;
{% endhint %}

## Section 1 - Series & Parallel Circuits (LD, LDI, OUT)

1. Code a logic when X0 is ON, Y0 should be ON and when X0 is OFF, Y0 should be OFF.<br>

   <figure><img src="/files/T2AKAdtDmkKfrWxK7bAX" alt="" width="139"><figcaption></figcaption></figure>
2. Code a series logic such that when X0 & X1 is ON, Y0 is ON<br>

   <figure><img src="/files/7NgD6Ns5LEtvCTdfMELw" alt="" width="184"><figcaption></figcaption></figure>
3. Code a Parallel Input logic such that when either of X0 or X1 is ON, Y0 is ON<br>

   <figure><img src="/files/yqO0TWzw9jm3uTHMJh8O" alt="" width="213"><figcaption></figcaption></figure>
4. Code a Parallel Output logic such that when X0 is ON, Y0 & Y1 are ON<br>

   <figure><img src="/files/UhxbQDkroCNfnm98Yx76" alt="" width="207"><figcaption></figcaption></figure>
5. Code a logic when X0 is ON, Y0 is ON & Y1 is OFF & when X0 is OFF, Y1 should be ON & Y0 should be OFF<br>

   <figure><img src="/files/KRestGVNHDKtGUv3eOLg" alt="" width="205"><figcaption></figcaption></figure>

## Section 2 - Latching & Interlocking Circuits – Using OUT Commands

1. Code a logic when X0 is pressed, Y0 should be latched & when X1 is Pressed, Y0 should be unlatched. (In this case consider X0 and X1 as NO Push Button)
2. Code a logic to interlock Y0 & Y1 using X0 & X1. Consider X0 & X1 as NO Push Buttons & use X2 as NC Push Button to reset Y0 & Y1.

## Section 3 - Latching & Interlocking Circuits – Using SET/RESET Commands

1. Code a logic when X0 is pressed, Y0 should be latched & when X1 is Pressed, Y0 should be unlatched. (In this case consider X0 and X1 as NO Push Button)
2. Code a logic to interlock Y0 & Y1 using X0 & X1. Consider X0 & X1 as NO Push Buttons & use X2 as NC Push Button to reset Y0 & Y1.

## Section 4 – Use to Timers (TMR)

1. Code a Logic such that when X0 is ON, Y0 gets ON after delay of 5 secs. When X0 is OFF, Y0 should be OFF&#x20;
2. Do the similar operation, but delay should change to 0.05 seconds (or 50ms)&#x20;
3. Do the similar operation, but delay should change to 0.005 seconds (or 5ms)&#x20;
4. Code a Logic when X0 is ON, Y0 gets ON after 3 seconds delay & then after delay of 3 more seconds Y1 should be on & after delay of 3 seconds Y2 should be ON.&#x20;
5. Code a Logic, when X0 is ON, Y0 is ON for 10 seconds then OFF.&#x20;
6. Code a Logic that can be used to start a Motor 1 (Y0) using X0 (NO) and then after a delay of 10 sec start Motor 2 (Y1). When the Motor 1 is switched off using X1(NC) there should be delay of 10 sec before the Motor 2 is off.
7. Code a Logic in which Y0 is ON (latch) only when X1 (NO) is ON in 10 sec. just after start of the Switch X0 (NO). Otherwise if X1 is pressed after 10 sec. Nothing should happen. Unlatch Y0 when X0 is OFF.

## Section 5- Use of Timers (TMR) with Comparison Commands

1. Use one push button (X0) to turn ON Y0 in following sequence: Y0 on for 2 sec. then off for 2 sec. then on for 3 sec. then continuously off.&#x20;
2. Use X0 to blink Y0. (On Time 0.5 second & OFF time 0.5 second).&#x20;
3. Use X0 to blink Y0. (On Time 0.5 second & OFF time 1 second).&#x20;
4. When you press X0, Y0 and Y1 should blink with the delay of 1 sec continuously (such that 1 sec. ON & 1 sec. OFF) and when you press X1, Y0 and Y1 should blink with the delay of 1.5 sec. (such that 1.5 sec. ON & 1.5 sec. OFF)&#x20;
5. Code a basic Traffic Light Simulator such that when you press X0 following sequence should occur

<figure><img src="/files/mOck3LXvYQQ7VyTJiBcv" alt="" width="369"><figcaption></figcaption></figure>

## Section 6- Use of Counters (CNT) with Comparators Commands

1. Code a logic such that When X0 is pressed 3 times, Y0 should be ON.&#x20;
2. Code a logic such that When X0 is pressed 3 times, Y0 should be ON & when X1 is pressed Y0 should be OFF (Use Counter reset command)&#x20;
3. Code a logic in which Sensor (X1) is being used to count the bottles on the conveyor (Y0) which is being latched by X0. Use X0 to latch the conveyor & after X1 counts 10, conveyor should be unlatched.&#x20;
4. Code a logic in which&#x20;
   * When X1 is pressed once– Y0 gets ON, Y1, Y2 get off,&#x20;
   * When X1 is pressed twice – Y1 gets ON and Y0, Y2 get OFF&#x20;
   * When X1 is pressed thrice – Y2 gets ON and Y0, Y1 get OFF&#x20;
   * When X1 is pressed fourth time, all outputs should be OFF & Cycle should repeat on pressing X1 again

## Section 7- Use of Data Register (D0) & related commands MOV, RST, ADD, SUB, MUL, DIV & INC/DEC

1. Switch ON a Lamp (Y0) after 5 sec. Make a provision using “MOV” command to change the delay time to 10 second by pressing X1 & then back to 5 sec by pressing X2. You have 1 maintained button (X0) and 2 push buttons only. Maintained button to switch on/off the lamp. Other two push button for changing the time from 5 to 10 sec and viceversa&#x20;
2. Code a logic to Change the time of above timer using Increment & (X3- PB) Decrement (X4- PB) commands.&#x20;
3. Code a logic to blink the output Y0 using X0 with following delay time sequence using MOV command a. Default Delay Time = ON time 1 Second & OFF Time 1 second b. Case A, When X1 is pressed = ON time 2 seconds & OFF time 1 second c. Case B, When X2 is pressed = ON time 1.5 seconds & OFF Time 2 seconds&#x20;
4. Code a logic as above but change the time using Increment (X1) & Decrement (X2) functions such that minimum blinking time should be 0.5 seconds (ON/OFF) & maximum should be 3 seconds (ON/OFF). The step of Increment & Decrement should be 0.1 second&#x20;
5. I have a constant 10 in D0&#x20;
   * Multiply it with 100&#x20;
   * Add 56 to it&#x20;
   * Subtract 14 from it&#x20;
   * Finally store it in D10


# Omron

### Online Course

On this page, you will find all the available resources for the Omron PLC Lessons which is available in the following course:&#x20;

{% embed url="<https://codeandcompile.com/course/learn-omron-plc-programming-using-cp1e>" %}

### PLC Software

The programming software which is required to program Omron CP1E PLC is **CxOne**. The link to download this software can be found at [Hardware and Software](/resources/hardware-and-software)

### Resources

The following are the various resources that are used in the web series These are extremely helpful as a reference guide.

<table><thead><tr><th width="185.45756746186936">Name</th><th width="150">Type<select><option value="494520ccb75949cca7a92310555f85de" label="pdf" color="blue"></option><option value="8fdd12a9343e43398eb2afe07e1a9a94" label="pptx" color="blue"></option><option value="e22ca6a79a304dcd98e420bad185843f" label="rar" color="blue"></option><option value="dc9d7bc629bb452f920d9d9460f1d826" label="TIA Portal file" color="blue"></option><option value="af32221477cc4bf3b1d904ca4af98977" label="txt" color="blue"></option><option value="60c16abee0bb4a2cbcde86a8e4e68038" label="others" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Course Presentation with exercises</td><td><span data-option="494520ccb75949cca7a92310555f85de">pdf</span></td><td><a href="/files/sl25aZDY9yFLVAWaIdAP">/files/sl25aZDY9yFLVAWaIdAP</a></td></tr></tbody></table>

### More information

Learn more about Omron PLC and Software at this page [Books and Guides](/resources/books-and-guides)


# PLCnext

On this page, you will find all the available resources for the course PLCnext - Next Generation PLC

### My experience with PLCnext

Back in 2020, I was contacted by Director of Marketing, Phoenix Contant [Ira Sharp](https://www.linkedin.com/search/results/all/?keywords=ira%20sharp%20jr\&origin=RICH_QUERY_SUGGESTION\&position=0\&searchId=0ad5d677-4ca5-42c2-b605-ae65d757531a\&sid=Y%40v) about testing a new product which has revolutionized the way we see PLC. That product was **PLCnext AXC F 2132**. Before working on PLCnext, I was working extensively on Siemens S7-1200, S7-1500 PLCs. And to make dashboard for my application I install Node-RED on the computer to link it further with Siemens PLCs via OPC UA. It was working great but its not always nice to carry a compuer just for the dashboard.&#x20;

<div align="left"><figure><img src="/files/rJKSrVcTkudl6mxNp5Rb" alt="PLCnext"><figcaption></figcaption></figure></div>

**Here comes PLCnext which solves this problem**. PLCnext comes with Linux architecture which supports all the Linux based application. This means, I can install Node-RED in the PLCnext and communicate with the PLC internally using OPC UA layer without needing any extra computer. Its not only just Node-RED, you can install various applications like MySQL, MQTT, Python and many more. You find it interesting?&#x20;

### Unboxing video

Check out the complete playlist on PLCnext starting from scratch:

{% embed url="<https://www.youtube.com/watch?ab_channel=RajvirSingh&list=PLTLcz6IpeLYLidXE0y6bIwD5cBRZp7dMt&v=NCxqFqnryZw>" %}

### PLCnext Simulation

Do you know, you can learn PLC progrmaming without need of a hardware. PLCnext Engineering supports PLC simulation for AXC F 2132 PLC for free. Learn more about that [here](https://www.plcnext-community.net/news/plcnext-engineer-simulation/?gclid=Cj0KCQjwjbyYBhCdARIsAArC6LJxxFKSuJBy_OGTM_GIAZqkSrMSW0oWkGO9kfQf3aSgvqrof7xGu8EaAo3rEALw_wcB)

### Online Course

Learn more about this PLC [here](https://www.deltaww.com/en-us/products/PLC-Programmable-Logic-Controllers/253) or check out my free course on PLCnext in the link below:

{% embed url="<https://codeandcompile.com/course/plcnext-next-generation-plc>" %}

### Resources

❤ Shout out to [Dave ](https://www.linkedin.com/in/dave-eifert/)for creating the presentation on PLCnext

<table data-header-hidden><thead><tr><th width="308.60927122534616">Title</th><th data-type="files"></th></tr></thead><tbody><tr><td>01: Introduction to Programming with PLCnext</td><td><a href="/files/vkRRVpCzOTiOZvQXwY9C">/files/vkRRVpCzOTiOZvQXwY9C</a></td></tr><tr><td>02: Getting started with ProfiCloud</td><td><a href="/files/8YGrYYb96t2Y2Y9EpeY2">/files/8YGrYYb96t2Y2Y9EpeY2</a></td></tr><tr><td>03: Getting started with OPC UA</td><td><a href="/files/Szh0Eiz2hUHdaalUCK6I">/files/Szh0Eiz2hUHdaalUCK6I</a></td></tr></tbody></table>

### More information

Learn more about PLCnext at this page [Books and Guides](/resources/books-and-guides)


# Siemens


# S7-200

On this page, you will find all the available resources for the course Siemens S7-200 PLC

### Online Course

On this page, you will find all the available resources for the course named Siemens S7-200 PLC (Basic):&#x20;

{% embed url="<https://codeandcompile.com/course/siemens-s7-200-plc>" %}

### PLC Software

Download the PLC software here [Hardware and Software](/resources/hardware-and-software)

### Resources

The following are the various resources that are used in the web series These are extremely helpful as a reference guide.

<table><thead><tr><th width="185.45756746186936">Name</th><th width="150">Type<select><option value="494520ccb75949cca7a92310555f85de" label="pdf" color="blue"></option><option value="8fdd12a9343e43398eb2afe07e1a9a94" label="pptx" color="blue"></option><option value="e22ca6a79a304dcd98e420bad185843f" label="rar" color="blue"></option><option value="dc9d7bc629bb452f920d9d9460f1d826" label="TIA Portal file" color="blue"></option><option value="af32221477cc4bf3b1d904ca4af98977" label="txt" color="blue"></option><option value="60c16abee0bb4a2cbcde86a8e4e68038" label="others" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Introduction to S7-200 PLC (Course slides)</td><td><span data-option="494520ccb75949cca7a92310555f85de">pdf</span></td><td><a href="/files/UtUpuW4MOQPdXVu1IDQW">/files/UtUpuW4MOQPdXVu1IDQW</a></td></tr><tr><td>PLC Exercise sheet</td><td><span data-option="494520ccb75949cca7a92310555f85de">pdf</span></td><td><a href="/files/eLukovZraA4IWUQQB0My">/files/eLukovZraA4IWUQQB0My</a></td></tr><tr><td>Solutions</td><td><span data-option="e22ca6a79a304dcd98e420bad185843f">rar</span></td><td><a href="/files/PcKXzD2yu9REQFzrS6NW">/files/PcKXzD2yu9REQFzrS6NW</a></td></tr></tbody></table>

### More information

Learn more about S7-200 PLC at this page [Books and Guides](/resources/books-and-guides)


# S7-1200 (Basic)

On this page, you will find all the available resources for the course Learn Siemens S7-1200 and KTP 400 HMI (Basic) from Scratch.

### Online Course

On this page, you will find all the available resources for the course named Learn Siemens S7-1200 PLC and HMI (Basic)

{% embed url="<https://codeandcompile.com/course/learn-siemens-s7-1200-and-hmi-basic>" %}
E-Learning course
{% endembed %}

### Course Presentation

[Course Presentations](/factory-automation/plc/siemens/s7-1200-basic/course-presentations)

[TIA Projects](/factory-automation/plc/siemens/s7-1200-basic/tia-projects)

### PLC Software

Download the TIA portal software directly from the Siemens website. If you are unable to find the link on the Siemens website, check out the software links here [Hardware and Software](/resources/hardware-and-software)

### More information

Learn more about S7-1200 PLC at this page [Books and Guides](/resources/books-and-guides)


# Course Presentations

The following are the presentations that are used in the course Learn Siemens S7-1200 and HMI from Scratch. You can use these presentations as a reference document for the course.

### 🚀 Download all files

{% file src="/files/1KP8YpQJ3njhhmN97hg0" %}
Get it all&#x20;
{% endfile %}

### 01: Introduction to S7-1200 and TIA Portal

<table data-header-hidden><thead><tr><th width="341.60927122534616">Title</th><th data-type="files"></th></tr></thead><tbody><tr><td>Introduction to S7-1200 PLC</td><td><a href="/files/c2zLgl3WG0F5LKU7nAh7">/files/c2zLgl3WG0F5LKU7nAh7</a></td></tr><tr><td>Introduction to TIA</td><td><a href="/files/81YEPJRjLQU8Ww7KZgRt">/files/81YEPJRjLQU8Ww7KZgRt</a></td></tr><tr><td>Network and branches</td><td><a href="/files/rM7ct0yeIpZKOVriaEee">/files/rM7ct0yeIpZKOVriaEee</a></td></tr></tbody></table>

### 02: Bit logic instructions

<table data-header-hidden><thead><tr><th width="343.81246400078186"></th><th data-type="files"></th></tr></thead><tbody><tr><td>Bit logic instructions</td><td><a href="/files/ZOE4BS87AgD51EJyJxpS">/files/ZOE4BS87AgD51EJyJxpS</a></td></tr><tr><td>Positive and negative edge</td><td><a href="/files/hYfGFgQ3HpbNXgDrxmvi">/files/hYfGFgQ3HpbNXgDrxmvi</a></td></tr><tr><td>Latching and unlatching</td><td><a href="/files/IpBAExIJIxfQQSlXPviy">/files/IpBAExIJIxfQQSlXPviy</a></td></tr></tbody></table>

### 03: Timers

<table data-header-hidden><thead><tr><th width="346.64315150094683"></th><th data-type="files"></th></tr></thead><tbody><tr><td>Pulse timer</td><td><a href="/files/QnsFPXhYQAGEUz2OIUEu">/files/QnsFPXhYQAGEUz2OIUEu</a></td></tr><tr><td>Timer ON delay</td><td><a href="/files/u2cKbFSXRicFDN40fn1X">/files/u2cKbFSXRicFDN40fn1X</a></td></tr><tr><td>Timer OFF delay</td><td><a href="/files/dgIwU6QJOvExBI4dpAcb">/files/dgIwU6QJOvExBI4dpAcb</a></td></tr><tr><td>Retentive timer</td><td><a href="/files/J2iFotmYWkboIFzZE8im">/files/J2iFotmYWkboIFzZE8im</a></td></tr><tr><td>Timer parameters</td><td><a href="/files/1TdtVcleeiw9bWHOcv3g">/files/1TdtVcleeiw9bWHOcv3g</a></td></tr></tbody></table>

### 04: Counters

<table data-header-hidden><thead><tr><th width="351"></th><th data-type="files"></th></tr></thead><tbody><tr><td>Count up</td><td><a href="/files/PY3wkPFBuxSAt9AxJ0Xx">/files/PY3wkPFBuxSAt9AxJ0Xx</a></td></tr><tr><td>Count down</td><td><a href="/files/1gP4BiOmV5gtahrXQkAc">/files/1gP4BiOmV5gtahrXQkAc</a></td></tr><tr><td>Count up-down</td><td><a href="/files/hped7JlN69TjdoPjQzuX">/files/hped7JlN69TjdoPjQzuX</a></td></tr><tr><td>Counter application</td><td><a href="/files/NidM91aH5Y3e3CmTf7ju">/files/NidM91aH5Y3e3CmTf7ju</a></td></tr></tbody></table>

### 05: Others

<table data-header-hidden><thead><tr><th width="355"></th><th data-type="files"></th></tr></thead><tbody><tr><td>Math</td><td><a href="/files/ZclY1G9LZPaaqbB6cH7p">/files/ZclY1G9LZPaaqbB6cH7p</a></td></tr><tr><td>Move</td><td><a href="/files/AZR2PsTTUvCPMhNF4cPm">/files/AZR2PsTTUvCPMhNF4cPm</a></td></tr><tr><td>Comparison</td><td><a href="/files/hlU0YH1bKwNktP5r4P2X">/files/hlU0YH1bKwNktP5r4P2X</a></td></tr><tr><td>Program control</td><td><a href="/files/65g7Mj0DGiWzua4nZ2wU">/files/65g7Mj0DGiWzua4nZ2wU</a></td></tr><tr><td>Word logic operation</td><td><a href="/files/VCZlgwVQzqUyZKlgBzG9">/files/VCZlgwVQzqUyZKlgBzG9</a></td></tr><tr><td>Shift and rotate</td><td><a href="/files/4tndTl02yrrqsRxGDts3">/files/4tndTl02yrrqsRxGDts3</a></td></tr><tr><td>PLC Safety circuit</td><td><a href="/files/f8yC44fBSc48AgzvFcyp">/files/f8yC44fBSc48AgzvFcyp</a></td></tr><tr><td>PLC Simulation</td><td><a href="/files/rNYbpydNH7JHXNSPJZox">/files/rNYbpydNH7JHXNSPJZox</a></td></tr><tr><td>Understanding HMI</td><td><a href="/files/NfEkrRBKlzgoGG8oQ3Bf">/files/NfEkrRBKlzgoGG8oQ3Bf</a></td></tr></tbody></table>

### 06: PID

{% file src="/files/teoKMwzQChuIXDmXXwV3" %}

### 07: Functions and Function blocks

<table><thead><tr><th></th><th data-type="files"></th></tr></thead><tbody><tr><td>Presentation</td><td><a href="/files/3PZLR7gMiCn8OwWYMmah">/files/3PZLR7gMiCn8OwWYMmah</a></td></tr><tr><td>PLC Program</td><td><a href="/files/c9I0Yt07G75F5gpOCa28">/files/c9I0Yt07G75F5gpOCa28</a></td></tr></tbody></table>


# TIA Projects

The following are the copy of TIA portal project being used in the course. The files are archived and can be easily retrieved úsing TIA Portal version 13 or later.

<table><thead><tr><th width="293.0353041174214">Title</th><th width="124">Type<select><option value="8b26f1a81bfc42ee95a6f944c238c39c" label="v13" color="blue"></option><option value="4525969bff394dceb516f675f76ebe66" label="rar" color="blue"></option><option value="bd2a8d2fad894be5a984224461afa54b" label="v16" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Assembler</td><td><span data-option="8b26f1a81bfc42ee95a6f944c238c39c">v13</span></td><td><a href="/files/pk7Mt4JVQWgU52IPMroG">/files/pk7Mt4JVQWgU52IPMroG</a></td></tr><tr><td>Trend view and data logging</td><td><span data-option="8b26f1a81bfc42ee95a6f944c238c39c">v13</span></td><td><a href="/files/6IIvL67Q276WG69gintM">/files/6IIvL67Q276WG69gintM</a></td></tr><tr><td>Assigning Authorization</td><td><span data-option="8b26f1a81bfc42ee95a6f944c238c39c">v13</span></td><td><a href="/files/OmXLZmtVb0XOXySQqOkn">/files/OmXLZmtVb0XOXySQqOkn</a></td></tr><tr><td>Recipe</td><td><span data-option="8b26f1a81bfc42ee95a6f944c238c39c">v13</span></td><td><a href="/files/qkXx9xXWVCKZW6Px7BLg">/files/qkXx9xXWVCKZW6Px7BLg</a></td></tr><tr><td>Using function key</td><td><span data-option="8b26f1a81bfc42ee95a6f944c238c39c">v13</span></td><td><a href="/files/7vdaR5fsHNEYP9R141G0">/files/7vdaR5fsHNEYP9R141G0</a></td></tr><tr><td>Sorting by weight</td><td><span data-option="8b26f1a81bfc42ee95a6f944c238c39c">v13</span></td><td><a href="/files/Rgx1p2w172bUDhD6SQ5b">/files/Rgx1p2w172bUDhD6SQ5b</a></td></tr><tr><td>3 Animations in HMI</td><td><span data-option="8b26f1a81bfc42ee95a6f944c238c39c">v13</span></td><td><a href="/files/qY2FDM3DVJ4PLWmdvdoZ">/files/qY2FDM3DVJ4PLWmdvdoZ</a></td></tr><tr><td>HMI Alarms</td><td><span data-option="4525969bff394dceb516f675f76ebe66">rar</span></td><td><a href="/files/Uw7RyRmo4yA4zVxnMuam">/files/Uw7RyRmo4yA4zVxnMuam</a></td></tr><tr><td>Functions and Function Blocks</td><td><span data-option="bd2a8d2fad894be5a984224461afa54b">v16</span></td><td><a href="/files/dgcml7NCbANffrH5b7V6">/files/dgcml7NCbANffrH5b7V6</a></td></tr></tbody></table>


# S7-1200 (Advanced)

In this page, you will find all the available resources for the course Learn Siemens S7-1200 and KTP 400 Advanced

### Online Course

On this page, you will find all the available resources for the course named Learn Siemens S7-1200 PLC and HMI (Advanced)

{% embed url="<https://codeandcompile.com/course/learn-siemens-s7-1200-plc-and-hmi-advanced>" %}
E-Learning course
{% endembed %}

### PLC Software

Download the TIA portal software directly from the Siemens website. If you are unable to find the link on the Siemens website, check out the software links here [Hardware and Software](/resources/hardware-and-software)

### More information

Learn more about S7-1200 PLC at this page [Books and Guides](/resources/books-and-guides)


# Course Presentation and Projects

The following are the presentations and TIA projects that are used in the course Learn Siemens S7-1200 (Advanced). You can use these presentations and projects as a reference document for the course.

### 01: Structure and UDT

<table data-header-hidden><thead><tr><th width="281.10730142768983">Title</th><th width="150">Type<select><option value="5e90d3717b434fdf8e558ca35b13e138" label="pptx" color="blue"></option><option value="43660003dcfb44a5a4b6c113a4b64533" label="pdf" color="blue"></option><option value="7093a191bfa54c798d61c5da9c49af5c" label="TIA Project" color="blue"></option><option value="72ebd2e3c6d645e697ab314f4f0de260" label="others" color="blue"></option><option value="5ff264ba46ca4daebc18a3b9ad7f9b71" label="rar" color="blue"></option><option value="9cb9f40966e840a3a19b4b81a209620b" label="factory io" color="blue"></option></select></th><th data-type="files">Download</th></tr></thead><tbody><tr><td>Structure and UDT presentation</td><td><span data-option="43660003dcfb44a5a4b6c113a4b64533">pdf</span></td><td><a href="/files/yfXMR1pmYNAh4MkEIKy6">/files/yfXMR1pmYNAh4MkEIKy6</a></td></tr><tr><td>Structure and UDT PLC Program</td><td><span data-option="43660003dcfb44a5a4b6c113a4b64533">pdf</span></td><td><a href="/files/R0nT0ujTte7Mt3qL6KC0">/files/R0nT0ujTte7Mt3qL6KC0</a></td></tr><tr><td>FACTORY IO Scene</td><td><span data-option="9cb9f40966e840a3a19b4b81a209620b">factory io</span></td><td><a href="/files/u3Twr9Mzo7TvTGFckSWp">/files/u3Twr9Mzo7TvTGFckSWp</a></td></tr></tbody></table>

### 02: Interfacing RFID with S7-1200

<table data-header-hidden><thead><tr><th width="250.54913800447247"></th><th width="150"><select><option value="69738008a64844c989848179b524031c" label="pdf" color="blue"></option><option value="14713e5ce7624f62bf7e0af5ce46f807" label="factoryio" color="blue"></option><option value="6e340a4d5b19463dbd6f6472a2a8382f" label="rar" color="blue"></option><option value="0be1ee0f3599492ea79a4febdd13e519" label="others" color="blue"></option><option value="82e640f9829e4eea8d2405b0e9bcf34d" label="TIA project" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>S7-1200 with RFID</td><td><span data-option="69738008a64844c989848179b524031c">pdf</span></td><td><a href="/files/uy9oPueqcq86Ss9HBkYy">/files/uy9oPueqcq86Ss9HBkYy</a></td></tr><tr><td>S7-1200 with RFID with FACTORY IO</td><td><span data-option="69738008a64844c989848179b524031c">pdf</span></td><td><a href="/files/FfaGcn3ElK8j0Sz8Py28">/files/FfaGcn3ElK8j0Sz8Py28</a></td></tr><tr><td>PLC Program (with FACTORY IO)</td><td><span data-option="6e340a4d5b19463dbd6f6472a2a8382f">rar</span></td><td><a href="/files/vD1y79MKzNUQOvPTKQ6h">/files/vD1y79MKzNUQOvPTKQ6h</a></td></tr><tr><td>S7-1200 with RFID without FACTORY IO</td><td><span data-option="69738008a64844c989848179b524031c">pdf</span></td><td><a href="/files/9Eh8CLYNL5Z42GtC5W1T">/files/9Eh8CLYNL5Z42GtC5W1T</a></td></tr><tr><td>PLC Program (without FACTORY IO)</td><td><span data-option="6e340a4d5b19463dbd6f6472a2a8382f">rar</span></td><td><a href="/files/HBN17D9AdAxPF748bElO">/files/HBN17D9AdAxPF748bElO</a></td></tr><tr><td>FACTORY IO (RFID)</td><td><span data-option="14713e5ce7624f62bf7e0af5ce46f807">factoryio</span></td><td><a href="/files/1GCajACXH3OdafFJCXrT">/files/1GCajACXH3OdafFJCXrT</a></td></tr><tr><td>FACTORY IO (RFID Application)</td><td><span data-option="14713e5ce7624f62bf7e0af5ce46f807">factoryio</span></td><td><a href="/files/IGVyfcyDWrEwov8iucHE">/files/IGVyfcyDWrEwov8iucHE</a></td></tr></tbody></table>

### 03: Interfacing SmartLight (IO-Link) with S7-1200

<table data-header-hidden><thead><tr><th width="286.60368752075703"></th><th width="199.88406138654386"><select><option value="76a7999520754e2ba1586bc0b9ec56b8" label="pdf" color="blue"></option><option value="7626b7fadf2248beaf5bb83e1783479c" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>S7-1200 with SmartLight</td><td><span data-option="76a7999520754e2ba1586bc0b9ec56b8">pdf</span></td><td><a href="/files/t2UEuDcODTHdNUYIBe3Y">/files/t2UEuDcODTHdNUYIBe3Y</a></td></tr><tr><td>PLC Program</td><td><span data-option="76a7999520754e2ba1586bc0b9ec56b8">pdf</span></td><td><a href="/files/KsZUtp5P7tVoHU020K1z">/files/KsZUtp5P7tVoHU020K1z</a></td></tr><tr><td>PLC Program</td><td><span data-option="7626b7fadf2248beaf5bb83e1783479c">rar</span></td><td><a href="/files/zQKNy2JEPikpq5GkXVil">/files/zQKNy2JEPikpq5GkXVil</a></td></tr></tbody></table>

### 04: Encode with a high-speed counter

<table data-header-hidden><thead><tr><th></th><th><select><option value="55c5550589e4498b95ffef128469b6c3" label="pdf" color="blue"></option><option value="1626e6fbb4e444ef8f02befaf24a1aec" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>S7-1200 with Encoder</td><td><span data-option="55c5550589e4498b95ffef128469b6c3">pdf</span></td><td><a href="/files/nSmqRSICt9CGtvnFh6FQ">/files/nSmqRSICt9CGtvnFh6FQ</a></td></tr><tr><td>Incremental encoder manual</td><td><span data-option="55c5550589e4498b95ffef128469b6c3">pdf</span></td><td><a href="/files/hBJVqVLY6YJHjIIgQ9Yt">/files/hBJVqVLY6YJHjIIgQ9Yt</a></td></tr><tr><td>PLC Program</td><td><span data-option="1626e6fbb4e444ef8f02befaf24a1aec">rar</span></td><td><a href="/files/DbRbagGGqtLPGnIlpnPd">/files/DbRbagGGqtLPGnIlpnPd</a></td></tr></tbody></table>

### 05: PLC to PLC Communication

<table data-header-hidden><thead><tr><th></th><th><select><option value="df9143fc6ef24f55b1a6b122d85bf7f5" label="pdf" color="blue"></option><option value="4cf5866193b9492e9526a5395d98de33" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>Interfacing two S7-1200 PLCs</td><td><span data-option="df9143fc6ef24f55b1a6b122d85bf7f5">pdf</span></td><td><a href="/files/ZSCx5LJix9VIkUH1II4B">/files/ZSCx5LJix9VIkUH1II4B</a></td></tr><tr><td>PLC Program</td><td><span data-option="df9143fc6ef24f55b1a6b122d85bf7f5">pdf</span></td><td><a href="/files/wI88V8lqk3vb61HYzH4u">/files/wI88V8lqk3vb61HYzH4u</a></td></tr><tr><td>PLC Program</td><td><span data-option="4cf5866193b9492e9526a5395d98de33">rar</span></td><td><a href="/files/rmPsneOMBb3vZNLuaX1r">/files/rmPsneOMBb3vZNLuaX1r</a></td></tr></tbody></table>

### 06: PROFINET Device status

<table data-header-hidden><thead><tr><th></th><th><select><option value="2639ac939afc417bba79d995e0cd1869" label="pdf" color="blue"></option><option value="a7d8ac47e1594feb9eca84bde957f896" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>Reading device status</td><td><span data-option="2639ac939afc417bba79d995e0cd1869">pdf</span></td><td><a href="/files/6GDPweiGoBUyU0aaa2Rb">/files/6GDPweiGoBUyU0aaa2Rb</a></td></tr><tr><td>PLC Program</td><td><span data-option="2639ac939afc417bba79d995e0cd1869">pdf</span></td><td><a href="/files/vvDmvOinDuVIDpLBlz40">/files/vvDmvOinDuVIDpLBlz40</a></td></tr><tr><td>PLC Program</td><td><span data-option="a7d8ac47e1594feb9eca84bde957f896">rar</span></td><td><a href="/files/1DMGMdhTOuYppeT8PN34">/files/1DMGMdhTOuYppeT8PN34</a></td></tr></tbody></table>

### 07: Siemens Web-Server

<table data-header-hidden><thead><tr><th></th><th><select><option value="f955d778137c4459b0cc6f25aa8224c4" label="pdf" color="blue"></option><option value="a16cb7d0f5424d70bc4f81cbbbf5d5a6" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>Webserver in S7-1200</td><td><span data-option="f955d778137c4459b0cc6f25aa8224c4">pdf</span></td><td><a href="/files/gicm7ixfNr6nwPosFUa1">/files/gicm7ixfNr6nwPosFUa1</a></td></tr><tr><td>More on webservers</td><td><span data-option="f955d778137c4459b0cc6f25aa8224c4">pdf</span></td><td><a href="/files/WnHgCT7zWug6co8jF5kp">/files/WnHgCT7zWug6co8jF5kp</a></td></tr><tr><td>PLC Program</td><td><span data-option="a16cb7d0f5424d70bc4f81cbbbf5d5a6">rar</span></td><td><a href="/files/rmPsneOMBb3vZNLuaX1r">/files/rmPsneOMBb3vZNLuaX1r</a></td></tr><tr><td>Supported web files</td><td><span data-option="a16cb7d0f5424d70bc4f81cbbbf5d5a6">rar</span></td><td><a href="/files/lGEcBNOwYDC7IgHOkno8">/files/lGEcBNOwYDC7IgHOkno8</a></td></tr></tbody></table>

### 08: Modbus Server and Client

<table data-header-hidden><thead><tr><th></th><th><select><option value="c6ecf279bd93449592b3cc14bf594c27" label="tiaportal" color="blue"></option><option value="53bae320dfc34e87ace243212504b642" label="" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>Modbus Client</td><td><span data-option="c6ecf279bd93449592b3cc14bf594c27">tiaportal</span></td><td><a href="/files/QW8m8cgaBqQIMSDzv6zJ">/files/QW8m8cgaBqQIMSDzv6zJ</a></td></tr></tbody></table>


# HMI Presentations and Projects

The following are the presentations and TIA projects that are used in the course Learn Siemens S7-1200 (Advanced). You can use these presentations and projects as a reference document for the course.

### 01: Scripts

<table><thead><tr><th></th><th><select><option value="0f979c2ee5c24e86b9a30f048d3066f1" label="pdf" color="blue"></option><option value="caeaa8571086406cb89c7b7a7182063a" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>Understanding Scripts</td><td><span data-option="0f979c2ee5c24e86b9a30f048d3066f1">pdf</span></td><td><a href="/files/UfBUJJdXgjy4vnhNkrFu">/files/UfBUJJdXgjy4vnhNkrFu</a></td></tr><tr><td>PLC Program</td><td><span data-option="0f979c2ee5c24e86b9a30f048d3066f1">pdf</span></td><td><a href="/files/ivhsgwBpQIvlgtsgUUK5">/files/ivhsgwBpQIvlgtsgUUK5</a></td></tr><tr><td>PLC Program</td><td><span data-option="caeaa8571086406cb89c7b7a7182063a">rar</span></td><td><a href="/files/A3u3WfG5Q3F0eCxsqG5f">/files/A3u3WfG5Q3F0eCxsqG5f</a></td></tr></tbody></table>

### 02: RFID Authorization

<table><thead><tr><th></th><th><select><option value="94e6d5d37edf40b992e896e19920e710" label="pdf" color="blue"></option><option value="e502ab6bd8814239b808e7d988d7c359" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>Authorize user via RFID Tag</td><td><span data-option="94e6d5d37edf40b992e896e19920e710">pdf</span></td><td><a href="/files/zB1Lshr9meqDad9UExPJ">/files/zB1Lshr9meqDad9UExPJ</a><a href="/files/CMy0WU5TBNjqC4zDKBfG">/files/CMy0WU5TBNjqC4zDKBfG</a></td></tr><tr><td>PLC Program <br>(Tag read/write)</td><td><span data-option="94e6d5d37edf40b992e896e19920e710">pdf</span></td><td><a href="/files/xnANqXuTCyzhPPzGrNg3">/files/xnANqXuTCyzhPPzGrNg3</a></td></tr><tr><td>PLC Program<br>(Tag read/write)</td><td><span data-option="e502ab6bd8814239b808e7d988d7c359">rar</span></td><td><a href="/files/o7vJ2WwT0CQLmMzaumeM">/files/o7vJ2WwT0CQLmMzaumeM</a></td></tr><tr><td>PLC Program<br>(user authorization)</td><td><span data-option="e502ab6bd8814239b808e7d988d7c359">rar</span></td><td><a href="/files/LDz5cqfQyHzK3Okp9toF">/files/LDz5cqfQyHzK3Okp9toF</a></td></tr></tbody></table>

### 03: Layouts in HMI&#x20;

<table><thead><tr><th></th><th><select><option value="723f7c59adf34dbfa5fce7b6a295b3db" label="pdf" color="blue"></option><option value="debf4acd744641918952fd2bdb828db8" label="rar" color="blue"></option></select></th><th data-type="files"></th></tr></thead><tbody><tr><td>Layouts in HMI</td><td><span data-option="723f7c59adf34dbfa5fce7b6a295b3db">pdf</span></td><td><a href="/files/uJmg2GDRKZxWDz5lRNDp">/files/uJmg2GDRKZxWDz5lRNDp</a></td></tr><tr><td>PLC program</td><td><span data-option="723f7c59adf34dbfa5fce7b6a295b3db">pdf</span></td><td><a href="/files/BbSvDeenrQGUP5FsjIhH">/files/BbSvDeenrQGUP5FsjIhH</a></td></tr><tr><td>PLC Program</td><td><span data-option="debf4acd744641918952fd2bdb828db8">rar</span></td><td><a href="/files/X1FtIXXe4siPGfcLh8kG">/files/X1FtIXXe4siPGfcLh8kG</a></td></tr></tbody></table>


# Codesys

CODESYS® is the leading manufacturer-independent IEC 61131-3 automation software for engineering control systems.

You will find all the resources available for the course Codesys made Easy on this pag&#x65;**.** This course is under construction and will be available soon at <https://www.codeandcompile.com.&#x20>;

### Online course

under construction

### Software

The software is free to use for learning and development purposes. The links to download the software can be found at [Hardware and Software](/resources/hardware-and-software)

### Hardware

Many hardware devices support codesys and can be used to run codesys programs. The following  are some examples:

* Wago PLC
* ctrlX CORE
* Raspberry Pi

### Exercises

Several exercises are explained and solved in the course Codesys made Easy. On the following page, you will find the unsolved exercises:

[Exercises - Part 1](/factory-automation/plc/codesys/exercises-part-1)


# Exercises - Part 1

Basic exercises on Codesys

{% hint style="warning" %}
In the following exercises, consider declaring the variables as follows.
{% endhint %}

<table><thead><tr><th width="157">Variable type</th><th width="121">Data type</th><th width="233">Variable declaration</th><th>Remarks</th></tr></thead><tbody><tr><td>Input, Output</td><td>Bool</td><td>xStart, xStop, xReset, xInput, xSensor, xInductiveSensor, xMotor, xSolenoid etc.</td><td></td></tr><tr><td>Value</td><td>Int or Int16</td><td>iCount, iLevel, iSpeed etc.</td><td></td></tr><tr><td>Value</td><td>DInt or Int32</td><td>diCount, diLevel, diOrderID etc.</td><td></td></tr><tr><td>Value</td><td>Real</td><td>rSpeed, rLevel, rHeight etc.</td><td></td></tr><tr><td>Name</td><td>String</td><td>sID, sRecipe, sPassword etc.</td><td></td></tr><tr><td>Parameter</td><td>Time</td><td>tDelay, tTimeout etc.</td><td></td></tr></tbody></table>

{% hint style="success" %}
**Solve the following exercises in the following programming languages:**\
\- Ladder Diagram\
\- FBD (Funcitonal Block Diagram)
{% endhint %}

## Section 1 - Series & Parallel logics

1. Write a program when bStart is TRUE, bMotor should be TRUE, and when bStart is False, bMotor should be FALSE.
2. Write a program to fulfill the following boolean table:

|          xStartA :BOOL (Input)         |          xStartB :BOOL (Input)         |        xOutputX : BOOL (Output)        |
| :------------------------------------: | :------------------------------------: | :------------------------------------: |
|  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |
|  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> |
| <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |
| <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> |

3. Write a program to fulfill the following boolean table:

|          xStartA :BOOL (Input)         |          xStartB :BOOL (Input)         |        xOutputX : BOOL (Output)        |
| :------------------------------------: | :------------------------------------: | :------------------------------------: |
|  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |  <mark style="color:red;">FALSE</mark> |
|  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> |
| <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> |
| <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> | <mark style="color:green;">TRUE</mark> |

4. Write a program to fulfill the following boolean table:

|          xStartA :BOOL (Input)         |        xOutputX : BOOL (Output)        |
| :------------------------------------: | :------------------------------------: |
|  <mark style="color:red;">FALSE</mark> | <mark style="color:green;">TRUE</mark> |
| <mark style="color:green;">TRUE</mark> |  <mark style="color:red;">FALSE</mark> |

5. Write a program to fulfill the following boolean table:

<table><thead><tr><th align="center">xStartA :BOOL (Input)</th><th width="251.33333333333331" align="center">xOutputX :BOOL (OUTPUT)</th><th align="center">xOutputY : BOOL (Output)</th></tr></thead><tbody><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr></tbody></table>

6. Write a program to fulfill the following boolean table:

<table><thead><tr><th align="center">xStartA :BOOL (Input)</th><th width="246.33333333333331" align="center">xOutputX :BOOL (OUTPUT)</th><th align="center">xOutputY : BOOL (Output)</th></tr></thead><tbody><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr></tbody></table>

7. Write a program to fulfill the following boolean table:

<table><thead><tr><th align="center">xStartA :BOOL (Input)</th><th width="246.33333333333331" align="center">xStartB :BOOL (Input)</th><th align="center">xOutputY : BOOL (Output)</th></tr></thead><tbody><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr></tbody></table>

## Section 2 - Latching and Interlocking logics using contacts

1. Write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched. \
   In this case, **consider xStart and xStop as NO Push Button.**
2. Write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched. \
   In this case, **consider xStart and xStop as NC Push Button.**
3. Write a program to interlock xSolenoidA (Output) and xSolenoidB (output). \
   \- When xStartA (Input) is pressed, xSolenoidA (output) should be latched, and xSolenoidB should be unlatched\
   \- When xStartB (Input) is pressed, xSolenoidB (output) should be latched, and xSolenoidA should be unlatched\
   \- When xStop (Input) is pressed, both solenoids should be unlatched\
   Consider **xStartA, xStartB as NO push button, and xStop as NC Push Button.**

## Section 3 -  RS and SR flip-flops

1. Using **RS flipflop** write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched.&#x20;
2. Using **SR flipflop** write a program when xStart (Input) is pressed, xMotor (output) should be latched & when xStop is Pressed, xMotor (output) should be unlatched.&#x20;
3. Realize the difference in operations when both the inputs xStart and xStop are TRUE. Which type of flipflop should be used ideally in this situation?

## Section 4- Use of Timers

{% hint style="info" %}
TON: On-delay timer; TOF: Off-delay timer
{% endhint %}

1. Write a program such that when xStart (Input) is TRUE, xMotor (Output) gets TRUE after a delay of 5 secs. When xStart is FALSE, xMotor should be FALSE.
2. Write a program when xStart (Input) is TRUE, xMotorA (Output) gets TRUE after 3 seconds delay, and then after a delay of 3 more seconds,  xMotorB (Output) should get TRUE & after a delay of 3 more seconds, xMotorC (Output) should get TRUE.&#x20;
3. Write a program if xStart (Input) is TRUE xMotor (Output) is TRUE for 10 seconds, then gets FALSE.&#x20;
4. Write a program such that:\
   \- xStart (Input) latches xMotorA (Output)\
   \- After a delay of 10 seconds, xMotorB (Output) latches\
   \- xStop (Input) unlatches xMotorA\
   \- After a delay of 10 seconds, xMotorB should get unlatched.
5. Write a program in which xMotorA (Output) latches only when xStartB (Input) is TRUE within 10 seconds just after the xStartA (Input) gets TRUE. Otherwise, if xStartB is TRUE after 10 seconds, nothing should happen. Unlatch xMotorA when xStartA is FALSE.

## Section 5- Use of Timers with Comparators&#x20;

{% hint style="info" %}
EQ: Equal\
NE: Not equal\
LT: Less than\
LE: Less than or equals\
GT: Greater than\
GE: Greater or equals &#x20;
{% endhint %}

1. Use one push button xStart (Input) actuate xMotor (Output) in the following sequence:\
   xMotor is TRUE for 2 seconds, then FALSE for 2 seconds, then TRUE for 3 seconds, then continuously FALSE.
2. Use xStartA (Input) to blink xLamp (Output) such that the On-time is 0.5 seconds and Off-time is 1 second.
3. Write a program such that:\
   \- When xStartA (Input) is TRUE, xLampA (Output) and xLampB should blink continuously with a delay of 1 second.\
   \- When xStartB (Input) is TRUE, xLampA (Output) and xLampB should blink continuously with a delay of 2 seconds.
4. Write a simple traffic light program to fulfill the following conditions. The Timer should reset, and the cycle should repeat when the time is above 25 seconds.

<table><thead><tr><th align="center">Time (in seconds)</th><th width="163" align="center">bRed (Output)</th><th width="175" align="center">bOrange (Output)</th><th align="center">bGreen (Output)</th></tr></thead><tbody><tr><td align="center">0 ~ 10</td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center">11 ~ 12</td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td></tr><tr><td align="center">13 ~ 23 </td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr><tr><td align="center">24 ~ 25</td><td align="center"><mark style="color:red;">FALSE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td><td align="center"><mark style="color:green;">TRUE</mark></td></tr></tbody></table>

## Section 6- Use of Counters with Comparators&#x20;

{% hint style="info" %}
CTU: Count Up\
CTD: Count Down
{% endhint %}

1. Write a program such that when xStart is pressed three times, xOutput should get TRUE. And when xReset is TRUE once, the xOutput should be FALSE, and the counter should RESET.&#x20;
2. Write a program to fulfill the following conditions:\
   \- When xStart is pressed once -xOutputA should be TRUE, xOutputB and xOutputC should be FALSE\
   \- When xStart is pressed again -xOutputB should be TRUE, xOutputA and xOutputC should be FALSE\
   \- When xStart is pressed again -xOutputC should be TRUE, xOutputA and xOutputB should be FALSE\
   \- When xStart is pressed again - all the outputs should be FALSE, and the cycle should repeat itself

## Section 7- Use of variables with Math Operators&#x20;

{% hint style="info" %}
ADD: Addition\
SUB: Subtraction\
MUL: Multiplication\
DIV: Division\
MOV: Move
{% endhint %}

1. Write a program to fulfill the following conditions:\
   \- xStart (Input) should latch the lamp xLamp (output) after five seconds delay.  \
   \- xStop (Input) should unlatch the xLamp\
   \- Use xTimeA (Input) to change the delay time to 10 seconds.\
   \- Use xTimeB (Input) to change the delay time to 5 seconds.

{% hint style="warning" %}
Use the Conversion command if necessary.
{% endhint %}

2. Write the same program as the above but instead of moving the constant time of 5 and 10 seconds. Use xInc (Input) to increment the time by 100ms and xDec (Input) to decrement the time by 100ms.&#x20;
3. Add a program to the solution of Exercise 7.2 to limit the minimum and maximum time to 1 second and 3 seconds, respectively.&#x20;
4. Write a program to blink the output xLamp with a delay of 1 second when xStart is TRUE.

## Section 8- Other operators&#x20;

{% hint style="info" %}
SEL: Bitwise selection\
MUX: Multiplexer\
LIMIT: Limit\
Conversion:&#x20;
{% endhint %}

1. Write a program using SEL such that the xAlarm (Output) should be TRUE if the iLevel (variable) is more than 80%. Take iLevel as an integer with the range of 0 to 100%. <mark style="color:red;">.</mark>
2. Use the operand LIMIT in exercise 7.3 to define the limits and realize the result.


# WAGO CC100

How to connect CC100 to AWS Cloud

{% file src="/files/K7uRXk0B6ttVrHMEn6k0" %}
Linked to the YouTube video
{% endfile %}


# Schneider

On this page, you will find all the available resources for the Schneider PLC course

### Online Course (In progress)

On this page, you will find all the available resources for the Schneider PLC course which is included in the course 'Learn 5 PLC's in a Day' and also exclusively on <https://www.codeandcompile.com>

### Course Presentation

* in progress..&#x20;

### PLC Software

Download the TIA portal software directly from the Schneider website. If you are unable to find the link on the Schneider website, check out the software links here [Hardware and Software](/resources/hardware-and-software)

### More information

Learn more about Schneider PLC on this page [Books and Guides](/resources/books-and-guides)

## PLC Exercises

{% content-ref url="/pages/00JpUlmHWRovy7izDNKy" %}
[PLC Exercises](/factory-automation/plc/schneider/plc-exercises)
{% endcontent-ref %}


# PLC Exercises

Practice your PLC Programming skills in EcoStructure Machine Expert Basic using the following exercises

{% hint style="info" %}
The solution to the exercises are given in the course titled Learn 5 PLC's in a Day and Schneider PLC Programming Course
{% endhint %}

## Section 1 - Series & Parallel logics

1. Create a logic when I0.0 is ON, Q0.0 should be ON and when I0.0 is OFF, Q0.0 should be OFF.&#x20;
2. Create a series logic such that when I0.0 & I0.1 are ON, Q0.0 is ON&#x20;
3. Create a Parallel Input logic such that when either of I0.0 or I0.1 is ON, Q0.0 is ON&#x20;
4. Create a Parallel Output logic such that when I0.0 is ON, Q0.0 & Q0.1 are ON&#x20;
5. Create a logic when I0.0 is ON, Q0.0 is ON & Q0.1 is OFF & when I0.0 is OFF, Q0.1 should be ON & Q0.0 should be OFF

## Section 2 - Latching & Interlocking – Using direct coil

1. Create a logic when I0.0 is pressed, Q0.0 should be latched & when I0.1 is Pressed, Q0.0 should be unlatched. (In this case consider I0.0 and I0.1 as NO Push Buttons)&#x20;
2. Create a logic to interlock Q0.0 & Q0.1 using I0.0 & I0.1. Consider I0.0 & I0.1 as NO Push Buttons & use I0.2 as NC Push Button to reset Q0.0 & Q0.1.

## Section 3 - Latching & Interlocking – Using SET/RESET coil

1. Create a logic when I0.0 is pressed, Q0.0 should be latched & when I0.1 is Pressed, Q0.0 should be unlatched. (In this case consider I0.0 and I0.1 as NO Push Button)
2. Create a logic to interlock Q0.0 & Q0.1 using I0.0 & I0.1. Consider I0.0 & I0.1 as NO Push Buttons & use I0.2 as NC Push Button to reset Q0.0 & Q0.1.

## Section 4 – Timers

1. Create a Logic such that when I0.0 is ON, Q0.0 gets ON after delay of 5 secs. When I0.0 is OFF, Q0.0 should be OFF
2. Do the similar operation, but delay should change to 0.05 seconds (or 50ms)
3. Do the similar operation, but delay should change to 0.005 seconds (or 5ms)
4. Create a Logic when:&#x20;
   * When I0.0 turns ON, Q0.0 will turn ON after 3 seconds.
   * After another 3 seconds, Q0.1 will turn ON.
   * After a final 3 seconds, Q0.2 will turn ON.
5. Create a Logic, when I0.0 is ON, Q0.0 is ON for 10 seconds then OFF.
6. Create a Logic that can be used to start a Motor 1 (Q0.0) using I0.0 (NO) and then after a delay of 10 sec start Motor 2 (Q0.1). When the Motor 1 is switched off using I0.1(NC) there should be delay  of 10 sec before the Motor 2 is off.
7. Create a logic where Q0.0 latches ON if I0.1 is pressed within 10 seconds of I0.0 turning ON. If I0.1 is pressed after 10 seconds, nothing happens. Q0.0 unlatches when I0.0 is turned OFF..

## Section 5- Timers (TMR) with Comparators&#x20;

1. Use one push button (I0.0) to turn ON Q0.0 in following sequence: Q0.0 on for 2 sec. then off for 2 sec. then on for 3 sec. then continuously off.
2. Use I0.0 to blink Q0.0. (On Time 0.5 second & OFF time 0.5 second).
3. Use I0.0 to blink Q0.0. (On Time 0.5 second & OFF time 1 second).
4. When I0.0 is pressed, Q0.0 and Q0.1 should blink with a 1 second ON and 1 second OFF cycle. When I0.1 is pressed, Q0.0 and Q0.1 should blink with a 1.5 second ON and 1.5 second OFF cycle.

### Section 6- Use of Counters (CNT) with Comparators&#x20;

1. Create a logic such that When I0.0 is pressed 3 times, Q0.0 should be ON.
2. Create a logic such that When I0.0 is pressed 3 times, Q0.0 should be ON & when I0.1 is pressed Q0.0 should be OFF (Use Counter reset command)
3. Create a logic where I0.0 latches the conveyor (Q0.0) ON. Sensor I0.1 counts bottles on the conveyor. After counting 10 bottles, the conveyor (Q0.0) unlatches.
4. Create a logic in which&#x20;
   * When I0.1 is pressed once– Q0.0 gets ON, Q0.1, Q0.2 get off,
   * When I0.1 is pressed twice – Q0.1 gets ON and Q0.0, Q0.2 get OFF
   * When I0.1 is pressed thrice – Q0.2 gets ON and Q0.0, Q0.1 get OFF
   * When I0.1 is pressed fourth time, all outputs should be OFF & cycle should repeat on pressing I0.1 again

## Section 7- Data Registers&#x20;

1. Switch ON the lamp (Q0.0) after a 5-second delay. Use the 'Assign' command to change the delay to 10 seconds when I0.1 is pressed, and back to 5 seconds when I0.2 is pressed. Use I0.0 (maintained button) to turn the lamp ON or OFF, and I0.1 and I0.2 (push buttons) to toggle the delay time between 5 and 10 seconds.
2. Update the logic of 7.1 where the delay time of the timer can be adjusted. Pressing I0.3 increments the timer by 0.1 second, and pressing I0.4 decrements it by 0.1 second. The current delay will either increase or decrease in steps of 0.1 second based on these inputs.
3. Create a logic to blink Q0.0 based on the following delay sequence using the 'Assign' command:
   * **Default:** ON time 1 second, OFF time 1 second.
   * **Case A:** When I0.1 is pressed, ON time 2 seconds, OFF time 1 second.
   * **Case B:** When I0.2 is pressed, ON time 1.5 seconds, OFF time 2 seconds.
4. Create a logic where Q0.0 blinks, and the ON/OFF times can be adjusted using the following:
   * **Default ON/OFF time:** 1 second.
   * **I0.1 (Increment):** Increases the ON/OFF time by 0.1 second.
   * **I0.2 (Decrement):** Decreases the ON/OFF time by 0.1 second.
   * **Time limits:** Minimum ON/OFF time is 0.5 seconds, and the maximum is 3 seconds.
5. Move a constant 10 in the register
   * Multiply it with 100&#x20;
   * Add 56 to it&#x20;
   * Subtract 14 from it&#x20;
   * Finally store it in the another data register


# Articles

In this page, you will find several articles related to PLC Programming




---

[Next Page](/llms-full.txt/1)

