[{"data":1,"prerenderedAt":9427},["ShallowReactive",2],{"blog-\u002Fblog\u002Fplc":3,"blog-all-for-related":4,"blog-all-plc":5},null,[],[6,266,1520,1983,2711,4008,4987,5479,6710,7298,8191],{"id":7,"title":8,"authors":9,"body":12,"cta":242,"date":246,"description":247,"extension":248,"image":249,"lastUpdated":3,"meta":250,"navigation":255,"path":256,"seo":257,"sitemap":258,"stem":259,"subtitle":260,"tags":261,"tldr":264,"video":3,"__hash__":265},"blog\u002Fblog\u002F2026\u002F06\u002Fplc-communication-latency-causes-and-fixes.md","Fixing PLC Communication Latency: Where the Milliseconds Really Go",[10,11],"drew-gatti","sumit-shinde",{"type":13,"value":14,"toc":229},"minimark",[15,19,22,25,30,33,36,40,43,46,49,52,81,84,88,91,94,97,101,110,130,134,137,140,172,175,178,181,185,188,191,194,197,200,204,207,210,213,216,219,223,226],[16,17,18],"p",{},"If you run control over a PLC link, a fast loop, an interlock, a setpoint that has to land on time, the fix usually isn't a faster runtime or a different protocol. It's a handful of settings made once at setup and never revisited, each one quietly costing milliseconds the loop can't spare.",[16,20,21],{},"Latency on a PLC link comes from how the data is handled, not the runtime, the network, or the PLC's CPU. Fix those settings, in order, and the timing comes back on its own.",[16,23,24],{},"This post follows the time: where a PLC link loses its milliseconds, and how to get each one back.",[26,27,29],"h2",{"id":28},"first-check-if-its-even-the-transport","First, check if it's even the transport",[16,31,32],{},"Following the time means starting at the bottom. Before you change anything, find out which layer is slow. You can spend a day tuning poll rates when the real problem is the protocol shaking underneath you, or the other way around.",[16,34,35],{},"The simplest check is a SISO test: single input, single output. Run a tiny exchange straight on the controller, with no PLC logic in the loop, just a line or two of code, and watch it on a scope. If even that bare exchange jumps around from one pass to the next, the problem is the transport itself, not anything you built on top. If the bare exchange holds steady but your real flow doesn't, the time is going somewhere in your data handling. That one test tells you which half of this article to read first.",[26,37,39],{"id":38},"the-data-doesnt-change-at-one-speed-and-your-poll-rate-shouldnt-either","The data doesn't change at one speed, and your poll rate shouldn't either",[16,41,42],{},"When the test points at your data handling, the first place to look is also where most of the lost time hides. It usually starts with a thirty-second choice: pick a scan rate, use it for every tag, move on. It works on day one, so it stays that way. But one rate is the wrong answer for almost every real system, and a quick calculation shows why.",[16,44,45],{},"Take a shared bus with twenty devices, all polled at 500 ms, where each read takes 50 ms. That's not 500 ms per device, it's a queue: twenty reads at 50 ms each is a full second to get through one cycle. By the time you read device twenty, its value is already a second old, and the next cycle hasn't started. You read a slow temperature sensor ten times before its value could have moved, and a fault bit that goes high for 800 ms can fall between two passes and never get seen. One rate ends up too fast for some tags and too slow for others.",[16,47,48],{},"The reason it's the wrong model is that the data isn't all one kind. A temperature drifts over minutes. A runtime counter ticks once an hour. An alarm bit can flip in under a second. A setpoint only changes when an operator touches it. Polling all four at the same rate fits none of them, and it wastes the controller's time on the ones that didn't need it.",[16,50,51],{},"The fix is to set the rate to how fast the data actually changes:",[53,54,55,63,69,75],"ul",{},[56,57,58,62],"li",{},[59,60,61],"strong",{},"Fast, 100 to 500 ms:"," fault and alarm bits, interlocks, values that drive closed-loop control. A missed change here has real consequences.",[56,64,65,68],{},[59,66,67],{},"Normal, 1 to 5 seconds:"," running values like flow, pressure, temperature, current draw. They change all the time, but not in an instant. A two-second poll catches the trend without flooding the bus.",[56,70,71,74],{},[59,72,73],{},"Slow, 30 seconds to a few minutes:"," counters, runtime hours, setpoints. They change by operator action, or build up slowly enough that fast polling is pure waste.",[56,76,77,80],{},[59,78,79],{},"Once, then cache:"," nameplate data, firmware versions, calibration values. Read them at startup and never poll again.",[16,82,83],{},"To sort any tag, ask whether a delay changes a control decision or only the timestamp on a record. If it changes a decision, it goes on the fast tier. If it only changes a timestamp, it's telemetry and belongs slower. Then ask how many tags really need the fast path, because it's almost always far fewer than the number on it now. Most points in most systems are reads, and most of those reads are not urgent.",[26,85,87],{"id":86},"a-timeout-is-a-measurement-not-a-guess","A timeout is a measurement, not a guess",[16,89,90],{},"Once the rates are sorted, the next thing that turns a slow moment into a stall is the timeout, and people usually set it by guessing a round number.",[16,92,93],{},"Both directions hurt. Too tight, and the request fails the moment the device is busy. That fires a retry, which adds more traffic to an already busy link, which makes the next request more likely to fail too. Too loose, and the master sits stuck on a dead request far longer than it should, holding up everything behind it. Either way, you've made latency.",[16,95,96],{},"The way to set it is to measure the floor and add margin. The floor has three parts: time to send the request, the device's own processing time, and time to send the response back. Take a slow serial device. Eight milliseconds to send, seventy-five for the device to process, twenty-five for the response: about 108 ms before anything has gone wrong. A 100 ms timeout fails that read every time. A 150 ms timeout usually passes but fails under load, which is the worst case because it's hard to catch. A 250 ms timeout gives you real room. Find your floor, multiply by 1.5 to 2, and don't treat the margin as wasted time. It's the difference between a link that holds under load and one that drops frames when the device gets busy. The datasheet gives you a starting number. A protocol analyzer gives you the real one.",[26,98,100],{"id":99},"the-controllers-scan-time-is-borrowed-so-spend-it-deliberately","The controller's scan time is borrowed, so spend it deliberately",[16,102,103,104,109],{},"Rates and timeouts are two settings, but step back and there's a simple idea underneath both. The PLC's first job is running the process, not talking to you. It works through a ",[105,106,108],"a",{"href":107},"\u002Fblog\u002F2025\u002F12\u002Fwhat-is-plc\u002F#the-scan-cycle","fixed scan",", and communication is squeezed in around the logic that actually drives the machine. Every request you send borrows time from that work. Set your rates and timeouts well and you're spending that borrowed time with care. Three habits waste it.",[53,111,112,118,124],{},[56,113,114,117],{},[59,115,116],{},"Polling more than you need."," This is the poll rate problem from the controller's side. A big set of points read at a fast rate burns budget on data that didn't need the rate, leaving less room for the data that does. Tiering isn't only about the bus. It gives the scan its time back.",[56,119,120,123],{},[59,121,122],{},"Ignoring the connection limit."," Many devices accept only a few connections at once, sometimes as few as one to four. Point too many clients at one device, or fire too many requests at once, and the extras wait in line or get turned away. Over TCP that shows up as connections backing off on a timer that climbs through 250, 500, then 1000 ms. It looks like random network latency, but it's the device turning work away because it ran out of sockets. Know the limit and stay under it.",[56,125,126,129],{},[59,127,128],{},"Stacking everything on one protocol."," Most PLCs run each protocol through its own driver and process, with its own share of resources. Put fast control data and high-volume telemetry on the same protocol and they fight over the same driver, so the fast path picks up the load from the slow path. It also helps to know which way each connection opens, whether the controller reaches out or something reaches in, because that changes how the work gets scheduled and what it costs.",[26,131,133],{"id":132},"match-the-protocol-to-the-data-not-the-other-way-around","Match the protocol to the data, not the other way around",[16,135,136],{},"Even with a driver to itself, none of the protocols a runtime reaches a PLC or device through at this level, the northbound, supervisory layer, are real-time by design. That's true of Modbus TCP, OPC UA, MQTT, and EtherNet\u002FIP's explicit messaging alike. They were built to move data reliably between a supervisory system and a controller, not to guarantee it lands inside a fixed time window. So there's no protocol to crown the winner here, only ones better or worse suited to the job in front of you.",[16,138,139],{},"Start with what each one is built for:",[53,141,142,148,154,160,166],{},[56,143,144,147],{},[59,145,146],{},"MQTT"," is pub\u002Fsub transport, built to move lots of telemetry, wrong for steady sub-loop response.",[56,149,150,153],{},[59,151,152],{},"OPC UA"," is strong for structured, modeled data and a poor fit for sub-100 ms control.",[56,155,156,159],{},[59,157,158],{},"WebSocket"," is light and often the quickest of the general-purpose options, but it makes no promise on turn time.",[56,161,162,165],{},[59,163,164],{},"Modbus TCP"," can hold steady low-millisecond reads in good conditions, but never as a hard promise.",[56,167,168,171],{},[59,169,170],{},"EtherNet\u002FIP's explicit messaging"," carries structured requests over standard Ethernet and can be tuned to hold a steady turn time, but it's making the same kind of effort the others are, not a different one.",[16,173,174],{},"None of these guarantees delivery inside a fixed time window by default. They're non-deterministic at this layer.",[16,176,177],{},"The real determinism in a PLC system lives one level down, inside the controller's own I\u002FO scan and the fieldbus underneath it, things like EtherCAT or PROFINET IRT, where timing is enforced by the hardware and the scan cycle itself, cycle after cycle, regardless of what's happening above it. A supervisory runtime doesn't poll that layer and doesn't reach it; it talks to the controller through one of the four protocols above. Treating EtherNet\u002FIP, or any of them, as carrying that hardware-level determinism up to the supervisory layer is where a \"pick protocol X and you're guaranteed real-time\" claim goes wrong.",[16,179,180],{},"So the answer isn't a ranking, it's a method. Pick a protocol the device actually supports and that's well implemented on both ends. Apply the techniques already in this article, tiered poll rates, measured timeouts, a respected scan budget, sampling and timestamping at the source, before touching the protocol at all. Only consider switching protocols if the timing still won't hold after that. Keep the fast path lean either way: carry only the points needed to make the decision, and fetch everything else after the fact from a database or a slower read. Most slow links come from reaching for a protocol swap before doing the work above it.",[26,182,184],{"id":183},"the-steadiest-timing-is-built-at-the-source-not-fixed-downstream","The steadiest timing is built at the source, not fixed downstream",[16,186,187],{},"Tiering, timeouts, and the work above all cut wasted time. But the steadiest timing comes from a change in where the work happens: do it in the PLC, at the source, instead of trying to fix it downstream over the network.",[16,189,190],{},"Start with sampling. If you need a fixed gap between readings, the network can't give it to you. MQTT won't, WebSocket won't, none of them will. Everything past the point where the signal is read is transport, and transport doesn't promise a fixed gap. So build the guarantee in at the source: have the controller sample at a fixed rate as it reads the signal, and stamp each reading with the time it was taken. Once a sample carries its own timestamp, it doesn't matter that the transport delivers it at an uneven pace, because the timing of the measurement is already saved. Trying to fix this by controlling when data lands over the wire is solving it in the wrong place.",[16,192,193],{},"That same move fixes the polling load. Instead of reading without pause, let the controller hold telemetry in a buffer and pull the buffer at the slower rate the data actually needs. The controller stops handling requests that never had to happen, and because each reading was already timestamped at the source, the slower, uneven pull never touches the timing of the data.",[16,195,196],{},"Then move the buffer in batches, not a trickle. Build an array, say a window of samples, each with a timestamp and value, and write the whole batch to a time-series database at once. These databases are built for batch writes, so this is far lighter on both the database and the controller than a stream of single writes. One thing to watch when you batch: build each request from registers that sit together. Stack points that are scattered across the register map into one request, and you force the device to read the dead space between them, or split the read into many small ones behind the scenes. Either way the cycle slows. Group points that are next to each other, and let the gaps fall on request edges.",[16,198,199],{},"And make sure the receiving end is built for the rate too. Reliability isn't only an upstream worry. A time-series database can take data at high speed, but feed it single writes at that speed and the cost climbs far above batched writes. Whatever takes the data, database, broker, or app, should be set up for the rate it's actually getting.",[26,201,203],{"id":202},"the-runtime-isnt-your-variable","The runtime isn't your variable",[16,205,206],{},"By the time poll rates, timeouts, protocol selection, and data handling are properly tuned, the runtime becomes just one fixed cost in the path, and a predictable one.",[16,208,209],{},"In the case of FlowFuse, which is built on Node-RED, the runtime runs on Node.js rather than on compiled embedded code. That introduces a small amount of overhead on each pass through a flow: typically a few milliseconds, and consistently so. It doesn't drift over time, and it doesn't increase when a device on the line becomes busy. A well-designed flow can maintain low-millisecond response times all day.",[16,211,212],{},"That fixed overhead is also a useful diagnostic tool. A constant delay of a few milliseconds cannot cause timing variations of tens of milliseconds. So if you're seeing swings that large, the root cause is somewhere else. In most cases, it comes down to one of the four issues covered in this article: an overloaded poll rate, a timeout chosen by guesswork, an ignored connection limit, or a protocol being asked to deliver timing guarantees it was never designed to provide.",[16,214,215],{},"There is one exception worth calling out. Node-RED runs as a single process with a shared event loop, so a CPU-intensive transformation or a slow database write anywhere within that instance can temporarily block everything else, including the fast path, whenever it executes. Moving that work to a different tab in the editor doesn't help, because all tabs within the same instance share the same event loop.",[16,217,218],{},"This isn't a case of the runtime being slow; it's a case of unrelated workloads competing for the same process. The solution is the same principle used throughout this article: give the fast path its own lane by moving heavy workloads into a separate instance.",[26,220,222],{"id":221},"final-thought","Final thought",[16,224,225],{},"A slow PLC link is the configuration assuming the data is simpler than it is. One rate for data that moves at four different speeds. A timeout that's never been measured. A scan budget spent without counting. A protocol asked to promise what it was never designed to promise.",[16,227,228],{},"None of that is a tool problem. It's a mismatch between what the system expects and what the data actually needs. Close that gap, by how fast each tag changes, by what the wire actually measures, by what each protocol was actually built for, and the timing follows on its own.",{"title":230,"searchDepth":231,"depth":231,"links":232},"",4,[233,235,236,237,238,239,240,241],{"id":28,"depth":234,"text":29},2,{"id":38,"depth":234,"text":39},{"id":86,"depth":234,"text":87},{"id":99,"depth":234,"text":100},{"id":132,"depth":234,"text":133},{"id":183,"depth":234,"text":184},{"id":202,"depth":234,"text":203},{"id":221,"depth":234,"text":222},{"type":243,"title":244,"description":245},"contact","Still seeing PLC latency, or not sure your runtime can keep up?","If you've worked through poll tiers, timeouts, and protocol splits and the link still isn't steady, or you're not sure whether your runtime can hold the timing your process needs, that's exactly what our team can help diagnose, and help you achieve with FlowFuse.","2026-06-17","Troubleshoot PLC communication latency by identifying common causes such as poll rates, timeout settings, connection limits, and protocol selection.","md","\u002Fblog\u002F2026\u002F06\u002Fimages\u002Ffixing-plc-communication.png",{"excerpt":251},{"type":13,"value":252},[253],[16,254,18],{},true,"\u002Fblog\u002F2026\u002F06\u002Fplc-communication-latency-causes-and-fixes",{"title":8,"description":247},{"loc":256},"blog\u002F2026\u002F06\u002Fplc-communication-latency-causes-and-fixes","Find the few settings draining your milliseconds and the timing follows.",[262,263],"post","plc","Most PLC latency isn't the runtime, the network, or the CPU, it's a few unexamined settings. Run a SISO test to isolate the transport from your data handling. Tier poll rates to how fast each tag actually changes instead of polling everything at one rate. Set timeouts from a measured floor times 1.5 to 2, not by feel. Spend the controller's scan budget deliberately: poll only what needs the fast tier, respect connection limits, and keep telemetry off the time-critical protocol's driver. At the supervisory layer, no protocol is a winner; pick one the device supports and that's well implemented on both ends, then hold timing with the techniques above before considering a switch. Then sample and timestamp at the source and batch writes instead of streaming single ones, so the timing is built in rather than fought for over the wire.","kBvB1M5H9MxzVcM_HRYw6JnMDJi-Y9bCDpGFByU8SPk",{"id":267,"title":268,"authors":269,"body":270,"cta":1500,"date":1503,"description":1504,"extension":248,"image":1505,"lastUpdated":1506,"meta":1507,"navigation":255,"path":1512,"seo":1513,"sitemap":1514,"stem":1515,"subtitle":1516,"tags":1517,"tldr":3,"video":3,"__hash__":1519},"blog\u002Fblog\u002F2026\u002F03\u002Fhow-to-connect-to-twincat-using-ads.md","How to Connect to Beckhoff TwinCAT PLC Using ADS (2026)",[11],{"type":13,"value":271,"toc":1480},[272,275,278,286,290,293,327,338,342,345,357,371,374,378,385,403,406,418,428,440,445,456,471,484,582,587,598,605,609,644,647,654,658,663,693,732,738,747,800,806,824,836,854,861,867,871,874,918,924,946,949,955,959,962,1007,1013,1026,1029,1034,1038,1041,1071,1077,1122,1125,1130,1134,1217,1220,1223,1228,1242,1249,1253,1283,1287,1303,1307,1322,1330,1335,1341,1355,1359,1362,1385,1391,1395,1410,1420,1435,1438,1453,1457,1460,1466,1469,1476],[16,273,274],{},"Beckhoff TwinCAT is one of the most widely deployed PLC platforms in industrial automation. ADS, its native communication protocol, gives you direct read and write access to PLC variables without additional licensing or middleware, and connecting from FlowFuse means tapping into that same channel TwinCAT uses internally.",[16,276,277],{},"The challenge is usually not the tooling. It is the routing layer. AMS Net IDs, route tables, firewall rules. Get any of those wrong and ADS fails without telling you why. This guide covers the routing first, before touching a single FlowFuse node, because that is where most people get stuck.",[16,279,280,281,285],{},"By the end you will have live TwinCAT variables flowing into ",[105,282,284],{"href":283},"\u002F","FlowFuse",".",[26,287,289],{"id":288},"prerequisites","Prerequisites",[16,291,292],{},"Before you begin, make sure you have the following in place:",[53,294,295,298,305,308,311,318,321,324],{},[56,296,297],{},"TwinCAT 3.1 runtime running on a Beckhoff IPC",[56,299,300,301,285],{},"FlowFuse running on an edge device with network access to the TwinCAT machine. If you don't have an account yet, [sign up]({% include \"sign-up-url.njk\" %}) to get started, then ",[105,302,304],{"href":303},"\u002Fblog\u002F2025\u002F09\u002Finstalling-node-red\u002F","follow this guide to quickly run a FlowFuse instance on your edge device",[56,306,307],{},"Both devices on the same network",[56,309,310],{},"Port 48898 open between the two devices",[56,312,313,317],{},[105,314,316],{"href":315},"#enable-symbol-creation","Symbol creation"," enabled on PlcTask so variables are accessible by name over ADS",[56,319,320],{},"PLC logged in and deployed on port 851",[56,322,323],{},"PLC in Run mode, the TwinCAT system tray icon must be green",[56,325,326],{},"Symbol paths of the variables you want to read or write, available from whoever wrote the PLC program",[328,329,330],"blockquote",{},[16,331,332,333,337],{},"If you don't have a real PLC available and want to follow along with a test setup, see\n",[105,334,336],{"href":335},"#setting-up-a-test-plc","Setting Up a Test PLC"," at the end of this guide before continuing.",[26,339,341],{"id":340},"what-is-ads-and-why-it-matters","What is ADS and Why It Matters",[16,343,344],{},"ADS, Automation Device Specification, is not an integration layer Beckhoff added for external tools. It is the internal communication backbone of the TwinCAT runtime itself. The same protocol TwinCAT XAE uses when you go online with a PLC, the same one the HMI uses to read variables, the same one the NC task uses to talk to the PLC task. When you connect from FlowFuse, you are using that same channel.",[16,346,347,348,352,353,356],{},"Every TwinCAT device has an AMS Net ID. It looks like an IP address with two extra octets: ",[349,350,351],"code",{},"10.68.82.232.1.1",". The first four typically match the device IP, the last two are almost always ",[349,354,355],{},"1.1"," by convention. This is how the ADS router identifies devices on the network, and it is what you will configure in every connection you make from FlowFuse.",[16,358,359,360,363,364,366,367,370],{},"Within a device, different TwinCAT components are reachable on different ADS ports. The PLC runtime listens on port ",[349,361,362],{},"851"," by default. If your machine runs multiple PLC tasks, each task gets its own port: the first task is ",[349,365,362],{},", the second is ",[349,368,369],{},"852",", and so on. Check with the controls engineer which port corresponds to the task containing your variables.",[16,372,373],{},"Three things cause silent failures: wrong AMS Net ID, missing route, blocked port 48898. ADS gives you nothing when any of these are wrong. No error, no timeout message, just silence. That is why we cover routing before touching a single FlowFuse node.",[26,375,377],{"id":376},"configuring-ads-routes","Configuring ADS Routes",[16,379,380,381,384],{},"TwinCAT will not accept an ADS connection from an unknown host. Every external device that needs to connect must be explicitly trusted in TwinCAT's route table. This is stored in a file called ",[349,382,383],{},"StaticRoutes.xml"," on the TwinCAT machine.",[16,386,387,388,391,392,395,396,398,399,402],{},"TwinCAT provides a route manager in the system tray under ",[59,389,390],{},"Router > Edit Routes",". However it does not expose the Flags setting, which defaults to ",[349,393,394],{},"64"," and will silently block connections from non-Windows devices such as Linux or Mac based edge devices. Editing ",[349,397,383],{}," directly is the only way to set Flags to ",[349,400,401],{},"0",", which allows connections from any trusted device on your network.",[16,404,405],{},"Before adding the route you need two pieces of information:",[53,407,408,411],{},[56,409,410],{},"The IP address of your FlowFuse edge device",[56,412,413,414,417],{},"The AMS Net ID you will assign to it, which is the IP address with ",[349,415,416],{},".1.1"," appended",[16,419,420,421,424,425,285],{},"For example if your FlowFuse device IP is ",[349,422,423],{},"10.68.82.101",", its AMS Net ID is ",[349,426,427],{},"10.68.82.101.1.1",[328,429,430],{},[16,431,432,435,436,439],{},[59,433,434],{},"Important:"," Your FlowFuse edge device must be on the same network as the interface TwinCAT's AMS Net ID is bound to. TwinCAT binds its AMS Net ID to a specific network interface on startup. If your machine has multiple network interfaces, confirm which IP the AMS Net ID uses, you can find it by right clicking the TwinCAT tray icon and selecting ",[59,437,438],{},"About TwinCAT System",". Your FlowFuse device must be reachable on that same network, otherwise the ADS handshake will fail even if port 48898 is open.",[16,441,442],{},[59,443,444],{},"Edit StaticRoutes.xml:",[328,446,447],{},[16,448,449,450,453,454,285],{},"If you do not have direct access to the TwinCAT machine, ask the controls engineer or machine builder to make this change. Share this section with them so they know exactly what needs to be set, particularly the ",[349,451,452],{},"Flags"," value of ",[349,455,401],{},[328,457,458],{},[16,459,460,463,464,466,467,470],{},[59,461,462],{},"Warning:"," The PowerShell command below overwrites the entire ",[349,465,383],{}," file. If the TwinCAT machine already has existing routes configured, back up the file before running this command or add your route entry manually inside the existing ",[349,468,469],{},"\u003CRemoteConnections>"," block instead.",[472,473,474,477],"ol",{},[56,475,476],{},"On the TwinCAT machine open PowerShell as administrator",[56,478,479,480,483],{},"Run the following command, replacing ",[349,481,482],{},"YOUR_EDGE_DEVICE_IP"," with the actual IP of your FlowFuse device:",[485,486,490],"pre",{"className":487,"code":488,"language":489,"meta":230,"style":230},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","$xml = @\"\n\u003C?xml version=\"1.0\"?>\n\u003CTcConfig xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\">\n  \u003CRemoteConnections>\n    \u003CRoute>\n      \u003CName>flowfuse-edge\u003C\u002FName>\n      \u003CAddress>YOUR_EDGE_DEVICE_IP\u003C\u002FAddress>\n      \u003CNetId>YOUR_EDGE_DEVICE_IP.1.1\u003C\u002FNetId>\n      \u003CType>TCP_IP\u003C\u002FType>\n      \u003CFlags>0\u003C\u002FFlags>\n    \u003C\u002FRoute>\n  \u003C\u002FRemoteConnections>\n\u003C\u002FTcConfig>\n\"@\n$xml | Set-Content \"C:\\Program Files (x86)\\Beckhoff\\TwinCAT\\3.1\\Target\\StaticRoutes.xml\"\n","powershell",[349,491,492,500,505,511,516,522,528,534,540,546,552,558,564,570,576],{"__ignoreMap":230},[493,494,497],"span",{"class":495,"line":496},"line",1,[493,498,499],{},"$xml = @\"\n",[493,501,502],{"class":495,"line":234},[493,503,504],{},"\u003C?xml version=\"1.0\"?>\n",[493,506,508],{"class":495,"line":507},3,[493,509,510],{},"\u003CTcConfig xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\">\n",[493,512,513],{"class":495,"line":231},[493,514,515],{},"  \u003CRemoteConnections>\n",[493,517,519],{"class":495,"line":518},5,[493,520,521],{},"    \u003CRoute>\n",[493,523,525],{"class":495,"line":524},6,[493,526,527],{},"      \u003CName>flowfuse-edge\u003C\u002FName>\n",[493,529,531],{"class":495,"line":530},7,[493,532,533],{},"      \u003CAddress>YOUR_EDGE_DEVICE_IP\u003C\u002FAddress>\n",[493,535,537],{"class":495,"line":536},8,[493,538,539],{},"      \u003CNetId>YOUR_EDGE_DEVICE_IP.1.1\u003C\u002FNetId>\n",[493,541,543],{"class":495,"line":542},9,[493,544,545],{},"      \u003CType>TCP_IP\u003C\u002FType>\n",[493,547,549],{"class":495,"line":548},10,[493,550,551],{},"      \u003CFlags>0\u003C\u002FFlags>\n",[493,553,555],{"class":495,"line":554},11,[493,556,557],{},"    \u003C\u002FRoute>\n",[493,559,561],{"class":495,"line":560},12,[493,562,563],{},"  \u003C\u002FRemoteConnections>\n",[493,565,567],{"class":495,"line":566},13,[493,568,569],{},"\u003C\u002FTcConfig>\n",[493,571,573],{"class":495,"line":572},14,[493,574,575],{},"\"@\n",[493,577,579],{"class":495,"line":578},15,[493,580,581],{},"$xml | Set-Content \"C:\\Program Files (x86)\\Beckhoff\\TwinCAT\\3.1\\Target\\StaticRoutes.xml\"\n",[328,583,584],{},[16,585,586],{},"Note: In this example, TwinCAT 3.1 is installed. If you are using a different version, replace 3.1 with the version installed on your system. The installation path may also vary depending on your TwinCAT setup.",[472,588,589,595],{"start":507},[56,590,591,592,285],{},"Restart the TwinCAT router from the system tray by right clicking the TwinCAT icon and selecting ",[59,593,594],{},"Router > Restart",[56,596,597],{},"Open the Windows Firewall and confirm that port 48898 is allowed for inbound TCP connections.",[16,599,600,601,604],{},"After the router restarts, verify that port 48898 is reachable from your FlowFuse edge device by running ",[349,602,603],{},"nc -zv \u003Ctwincat-ip> 48898",". If the connection is refused, confirm the firewall rule was saved and that both devices are on the same subnet.",[26,606,608],{"id":607},"installing-node-red-contrib-ads-client-in-flowfuse","Installing node-red-contrib-ads-client in FlowFuse",[472,610,611,614,620,627,633,639],{},[56,612,613],{},"In your FlowFuse instance open the Node-RED editor",[56,615,616,617],{},"Click the hamburger menu in the top right and select ",[59,618,619],{},"Manage Palette",[56,621,622,623,626],{},"Go to the ",[59,624,625],{},"Install"," tab",[56,628,629,630],{},"Search for ",[349,631,632],{},"node-red-contrib-ads-client",[56,634,635,636,638],{},"Click ",[59,637,625],{}," and wait for it to complete",[56,640,635,641],{},[59,642,643],{},"Close",[16,645,646],{},"Once the installation is complete, a few nodes will appear in the right-hand palette under the TwinCAT ADS category.",[16,648,649],{},[650,651],"img",{"alt":652,"src":653},"TwinCAT ADS nodes available in the Node-RED palette after installing node-red-contrib-ads-client","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Ftwincat-ads-nodes.png",[26,655,657],{"id":656},"connecting-to-twincat","Connecting to TwinCAT",[16,659,660],{},[59,661,662],{},"Add the connection node:",[472,664,665,672,675,686],{},[56,666,667,668,671],{},"In Node-RED drag an ",[59,669,670],{},"ADS – Connection Status"," node onto the canvas",[56,673,674],{},"Double click it to open the configuration",[56,676,677,678,681,682,685],{},"Next to the ",[59,679,680],{},"Connection"," field click ",[59,683,684],{},"+"," to create a new connection",[56,687,688,689,692],{},"In the ",[59,690,691],{},"Required Settings"," tab fill in the Target AMS Net ID and Target ADS Port:",[694,695,696,709],"table",{},[697,698,699],"thead",{},[700,701,702,706],"tr",{},[703,704,705],"th",{},"Field",[703,707,708],{},"Value",[710,711,712,723],"tbody",{},[700,713,714,718],{},[715,716,717],"td",{},"Target AMS Net ID",[715,719,720,721],{},"AMS Net ID of your TwinCAT machine, e.g. ",[349,722,351],{},[700,724,725,728],{},[715,726,727],{},"Target ADS Port",[715,729,730],{},[349,731,362],{},[16,733,734],{},[650,735],{"alt":736,"src":737},"Required settings tab showing Target AMS Net ID and Target ADS Port fields in the ADS connection configuration","\u002Fblog\u002F2026\u002F03\u002Fimages\u002FTwincat-config-required-fields.png",[472,739,740],{"start":518},[56,741,742,743,746],{},"Switch to the ",[59,744,745],{},"Optional Settings"," tab and fill in the network settings:",[694,748,749,757],{},[697,750,751],{},[700,752,753,755],{},[703,754,705],{},[703,756,708],{},[710,758,759,770,780,790],{},[700,760,761,764],{},[715,762,763],{},"Router Address",[715,765,766,767],{},"IP address of your TwinCAT machine, e.g. ",[349,768,769],{},"10.68.82.232",[700,771,772,775],{},[715,773,774],{},"Router TCP Port",[715,776,777],{},[349,778,779],{},"48898",[700,781,782,785],{},[715,783,784],{},"Local AMS Net ID",[715,786,787,788],{},"AMS Net ID of your FlowFuse edge device, e.g. ",[349,789,427],{},[700,791,792,795],{},[715,793,794],{},"Local ADS Port",[715,796,797],{},[349,798,799],{},"32750",[16,801,802],{},[650,803],{"alt":804,"src":805},"Optional settings tab showing Router Address, Router TCP Port, Local AMS Net ID and Local ADS Port fields","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Ftwincat-config-optional-tab.png",[16,807,808,809,811,812,814,815,817,818,820,821,823],{},"The ",[59,810,763],{}," and ",[59,813,774],{}," allow the ADS client to reach the TwinCAT router over the network. The ",[59,816,784],{}," identifies your FlowFuse edge device inside the ADS routing system and must match the route configured in ",[349,819,383],{},". The ",[59,822,794],{}," defines the local ADS endpoint used by the client and normally does not need to be changed.",[328,825,826],{},[16,827,828,831,832,835],{},[59,829,830],{},"Note:"," If your TwinCAT system is in config mode or the PLC runtime takes time to initialize on startup, enable ",[59,833,834],{},"Allow Half Open"," in the connection settings. Without it the client performs a strict system state check on connect and will fail with ADS error 7 even if the router is reachable. With it enabled the client connects regardless and waits for the runtime to become ready.",[472,837,838,844,849],{"start":524},[56,839,635,840,843],{},[59,841,842],{},"Add"," to save the connection configuration",[56,845,635,846],{},[59,847,848],{},"Done",[56,850,635,851],{},[59,852,853],{},"Deploy",[16,855,856,857,860],{},"Within a few seconds the connection status node should show ",[59,858,859],{},"connected",", indicating that FlowFuse successfully established an ADS session with the TwinCAT runtime.",[16,862,863],{},[650,864],{"alt":865,"src":866},"ADS connection status node showing connected state in Node-RED","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fconnection-status.png",[26,868,870],{"id":869},"reading-plc-variables","Reading PLC Variables",[16,872,873],{},"With the connection working, reading a variable takes three nodes: an inject node to trigger the read, a read value node to fetch the value, and a debug node to see the output.",[472,875,876,882,885,889,894,897,903],{},[56,877,878,879,671],{},"Drag an ",[59,880,881],{},"inject",[56,883,884],{},"Double click it and leave the default settings so it triggers manually",[56,886,635,887],{},[59,888,848],{},[56,890,878,891,671],{},[59,892,893],{},"ADS - Read Value",[56,895,896],{},"Double click it to configure",[56,898,899,900,902],{},"Select your TwinCAT connection from the ",[59,901,680],{}," dropdown",[56,904,905,906,909,910,913,914,917],{},"Set the ",[59,907,908],{},"Variable name"," to the full symbol path of the variable you want to read. Symbol paths are always in the format ",[349,911,912],{},"ProgramName.VariableName",". If you are following along with the test PLC, use ",[349,915,916],{},"MAIN.temperature",". If you are connecting to a real PLC, use the symbol paths provided by the controls engineer.",[16,919,920],{},[650,921],{"alt":922,"src":923},"ADS Read Value node configuration showing variable name set to MAIN.temperature","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fads-read-value.png",[472,925,926,930,936,939,942],{"start":536},[56,927,635,928],{},[59,929,848],{},[56,931,932,933,671],{},"Drag a ",[59,934,935],{},"debug",[56,937,938],{},"Connect the inject node output to the read value node input",[56,940,941],{},"Connect the read value node output to the debug node input",[56,943,635,944],{},[59,945,853],{},[16,947,948],{},"Click the inject button. You should see the variable value appear in the debug panel.",[950,951],"lite-youtube",{"videoid":952,"style":953,"title":954},"wTRmgIyWLyk","width: 100%; aspect-ratio: 16\u002F9; background-image: url('\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fads-read.png'); background-size: cover; background-position: center;","Reading TwinCAT PLC Variables with FlowFuse",[26,956,958],{"id":957},"subscribing-to-variable-changes","Subscribing to Variable Changes",[16,960,961],{},"Polling on a fixed timer works but is inefficient. For live data the better approach is to subscribe to variable changes. TwinCAT sends a new value to FlowFuse only when the value actually changes, which reduces unnecessary network traffic and gives you lower latency updates.",[472,963,964,969,971,975,984,998],{},[56,965,878,966,671],{},[59,967,968],{},"ADS - Subscribe Value",[56,970,896],{},[56,972,899,973,902],{},[59,974,680],{},[56,976,905,977,979,980,983],{},[59,978,908],{}," to the full symbol path of the variable you want to monitor. If you are following along with the test PLC, use ",[349,981,982],{},"MAIN.motorRunning",", it toggles roughly once per second so you will see true and false values arriving in the debug panel without being overwhelmed.",[56,985,905,986,989,990,993,994,997],{},[59,987,988],{},"Subscription mode"," to ",[59,991,992],{},"On Change",". This tells the TwinCAT runtime to notify FlowFuse only when the variable value has actually changed, rather than pushing the value on every cycle regardless of whether it changed. If you need a value delivered at a fixed interval even when unchanged, use ",[59,995,996],{},"Cyclic"," instead.",[56,999,905,1000,989,1003,1006],{},[59,1001,1002],{},"Cycle time",[349,1004,1005],{},"100"," milliseconds. This is how frequently TwinCAT checks for changes on its side.",[16,1008,1009],{},[650,1010],{"alt":1011,"src":1012},"ADS Subscribe Value node configuration showing variable name, subscription mode set to On Change, and cycle time set to 100ms","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fads-subscribe.png",[472,1014,1015,1019,1022],{"start":530},[56,1016,635,1017],{},[59,1018,848],{},[56,1020,1021],{},"Connect its output to a debug node",[56,1023,635,1024],{},[59,1025,853],{},[16,1027,1028],{},"The debug node will now receive a message every time the variable value changes in the PLC, with no polling required from FlowFuse.",[950,1030],{"videoid":1031,"style":1032,"title":1033},"JYrzRXCHb9Q","width: 100%; aspect-ratio: 16\u002F9; background-image: url('\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fads-subscribe-image.png'); background-size: cover; background-position: center;","Subscribing to TwinCAT PLC Variable Changes with FlowFuse",[26,1035,1037],{"id":1036},"writing-to-plc-variables","Writing to PLC Variables",[16,1039,1040],{},"Writing back to the PLC closes the loop. This is useful for sending setpoints, commands, or reset signals from FlowFuse back to TwinCAT.",[472,1042,1043,1048,1050,1053,1061],{},[56,1044,878,1045,671],{},[59,1046,1047],{},"ADS - Write Value",[56,1049,896],{},[56,1051,1052],{},"Select your TwinCAT connection",[56,1054,905,1055,1057,1058,285],{},[59,1056,908],{}," to the full symbol path of the variable you want to write to. If you are following along with the test PLC, use ",[349,1059,1060],{},"MAIN.setpoint",[56,1062,1063,1064,1067,1068,1070],{},"Leave ",[59,1065,1066],{},"Automatically fill missing properties (autoFill)"," unchecked. This setting only applies when writing complex types such as structs or function blocks, it reads the current value from the PLC first and merges your changes on top so unspecified fields are not zeroed out. For a simple variable like ",[349,1069,1060],{}," it has no effect.",[16,1072,1073],{},[650,1074],{"alt":1075,"src":1076},"ADS Write Value node configuration showing variable name set to MAIN.setpoint with autoFill unchecked","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fads-write.png",[472,1078,1079,1083,1087,1108,1112,1115,1119],{"start":524},[56,1080,635,1081],{},[59,1082,848],{},[56,1084,878,1085,671],{},[59,1086,881],{},[56,1088,1089,1090,1093,1094,1097,1098,1101,1102,1105,1106,285],{},"Double click it and set the payload type to match the type of your PLC variable. The payload type must match what the PLC expects, a ",[59,1091,1092],{},"Number"," for INT or REAL, a ",[59,1095,1096],{},"boolean"," for BOOL, a ",[59,1099,1100],{},"string"," for STRING, and so on. If you are following along with the test PLC, ",[349,1103,1104],{},"setpoint"," is declared as INT so set the payload type to ",[59,1107,1092],{},[56,1109,635,1110],{},[59,1111,848],{},[56,1113,1114],{},"Connect the inject node output to the write node input",[56,1116,635,1117],{},[59,1118,853],{},[56,1120,1121],{},"Click the inject button to trigger the write",[16,1123,1124],{},"To verify the write worked, add a read value node for the same variable and check that the value updated in the debug panel.",[950,1126],{"videoid":1127,"style":1128,"title":1129},"f0GtEp6OA_M","width: 100%; aspect-ratio: 16\u002F9; background-image: url('\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fads-write-image.png'); background-size: cover; background-position: center;","Writing to TwinCAT PLC Variables with FlowFuse",[26,1131,1133],{"id":1132},"troubleshooting","Troubleshooting",[53,1135,1136,1154,1175,1181,1190,1199,1208],{},[56,1137,1138,1141,1142,1144,1145,1147,1148,1150,1151,1153],{},[59,1139,1140],{},"Connection fails silently with no error","\nThe FlowFuse device IP is not in ",[349,1143,383],{}," or ",[349,1146,452],{}," is set to ",[349,1149,394],{}," instead of ",[349,1152,401],{},". Edit the file using the PowerShell command in the routing section, then restart the TwinCAT router.",[56,1155,1156,1159,1160,1162,1163,1165,1166,1168,1169,1171,1172,1174],{},[59,1157,1158],{},"ADS error 7: Target machine not found","\nThe most common cause is that your FlowFuse device and the TwinCAT machine are not on the same network as the interface TwinCAT's AMS Net ID is bound to. Check the AMS Net ID in ",[59,1161,438],{}," on the TwinCAT machine and confirm your FlowFuse device has an IP on that same subnet. Also confirm the FlowFuse device IP is in ",[349,1164,383],{}," with ",[349,1167,452],{}," set to ",[349,1170,401],{},", and that the router was restarted after any changes. If the PLC runtime takes time to initialize on startup, enable ",[59,1173,834],{}," in the connection node.",[56,1176,1177,1180],{},[59,1178,1179],{},"Error: Connection to 127.0.0.1:48898 failed","\nThe Router Address field in the connection node is empty or incorrect. Open the connection node, set the Router Address to the TwinCAT machine IP, and redeploy.",[56,1182,1183,1186,1187,1189],{},[59,1184,1185],{},"Error 1808: Symbol not found","\nThe variable name is wrong or does not exist in the PLC program. Double check the full symbol path including the program name prefix, for example ",[349,1188,916],{},". If you are using the test PLC, make sure symbol creation is enabled in PlcTask and the PLC is in Run mode.",[56,1191,1192,1195,1196,1198],{},[59,1193,1194],{},"Error 1804: Failed to get fingerprint","\nThe FlowFuse device IP is missing from ",[349,1197,383],{}," or the TwinCAT router was not restarted after editing the file.",[56,1200,1201,1204,1205,1207],{},[59,1202,1203],{},"Port 48898 not reachable","\nPort 48898 is blocked on the TwinCAT machine firewall or the two devices are not on the same network. Confirm the firewall rule is in place and test reachability with ",[349,1206,603],{}," from your FlowFuse device.",[56,1209,1210,1213,1214,285],{},[59,1211,1212],{},"PLC variables not updating","\nThe PLC is not in Run mode. The TwinCAT system tray icon must be green. A blue icon means the runtime is stopped, right click the tray icon and select ",[59,1215,1216],{},"Restart TwinCAT (Run Mode)",[26,1218,336],{"id":1219},"setting-up-a-test-plc",[16,1221,1222],{},"This section is for readers who do not have a real TwinCAT PLC available and want to set up a minimal test environment to follow along with this guide. If you already have a PLC running, you do not need this section.",[1224,1225,1227],"h3",{"id":1226},"what-you-need","What You Need",[53,1229,1230,1233],{},[56,1231,1232],{},"A Windows machine or laptop",[56,1234,1235,1236],{},"TwinCAT XAE Shell installed. Download it from the ",[105,1237,1241],{"href":1238,"rel":1239},"https:\u002F\u002Fwww.beckhoff.com",[1240],"nofollow","Beckhoff website",[328,1243,1244],{},[16,1245,1246,1248],{},[59,1247,434],{}," If your Windows machine has Hyper-V enabled, TwinCAT will not run in KM mode and the system tray icon will stay blue instead of turning green. Make sure Hyper-V is disabled before proceeding. You may need to restart the machine after disabling it.",[1224,1250,1252],{"id":1251},"create-the-project","Create the Project",[472,1254,1255,1258,1263,1273],{},[56,1256,1257],{},"Open TwinCAT XAE Shell",[56,1259,635,1260],{},[59,1261,1262],{},"File > New > Project",[56,1264,1265,1266,1269,1270],{},"Select ",[59,1267,1268],{},"TwinCAT Projects"," then ",[59,1271,1272],{},"TwinCAT XAE Project",[56,1274,1275,1276,1279,1280],{},"Give the project a name, for example ",[349,1277,1278],{},"AdsDemo",", and click ",[59,1281,1282],{},"OK",[1224,1284,1286],{"id":1285},"add-a-plc-project","Add a PLC Project",[472,1288,1289,1295],{"start":518},[56,1290,1291,1292],{},"In Solution Explorer right click the project name and select ",[59,1293,1294],{},"Add New Item",[56,1296,1265,1297,1300,1301],{},[59,1298,1299],{},"Standard PLC Project",", give it a name, and click ",[59,1302,842],{},[1224,1304,1306],{"id":1305},"write-the-plc-program","Write the PLC Program",[472,1308,1309,1319],{"start":530},[56,1310,1311,1312,1315,1316],{},"In Solution Explorer expand ",[59,1313,1314],{},"PLC > your project > POUs"," and double click ",[59,1317,1318],{},"MAIN",[56,1320,1321],{},"In the declaration section (top panel) replace the existing content with:",[485,1323,1328],{"className":1324,"code":1326,"language":1327},[1325],"language-text","PROGRAM MAIN\nVAR\n    temperature : REAL := 23.5;\n    motorRunning : BOOL := FALSE;\n    setpoint : INT := 100;\n    cycleCount : INT := 0;\nEND_VAR\n","text",[349,1329,1326],{"__ignoreMap":230},[472,1331,1332],{"start":542},[56,1333,1334],{},"In the program body (bottom panel) add:",[485,1336,1339],{"className":1337,"code":1338,"language":1327},[1325],"temperature := temperature + 0.1;\nIF temperature > 100.0 THEN\n    temperature := 0.0;\nEND_IF\n\ncycleCount := cycleCount + 1;\nIF cycleCount >= 1000 THEN\n    motorRunning := NOT motorRunning;\n    cycleCount := 0;\nEND_IF\n",[349,1340,1338],{"__ignoreMap":230},[16,1342,1343,1344,1347,1348,1351,1352,1354],{},"This gives you three live variables to work with. ",[349,1345,1346],{},"temperature"," increments continuously every PLC cycle, ",[349,1349,1350],{},"motorRunning"," toggles roughly once per second, and ",[349,1353,1104],{}," stays static until you write to it from FlowFuse.",[1224,1356,1358],{"id":1357},"enable-symbol-creation","Enable Symbol Creation",[16,1360,1361],{},"Symbol creation must be enabled for ADS to access variables by name. Without this step the ADS client will connect successfully but fail to find any variables.",[472,1363,1364,1374,1381],{"start":548},[56,1365,1366,1367,1370,1371],{},"In Solution Explorer expand the project, then under ",[59,1368,1369],{},"Task"," double click ",[59,1372,1373],{},"PlcTask",[56,1375,1376,1377,1380],{},"Check ",[59,1378,1379],{},"Create symbols"," in the properties window that opens",[56,1382,635,1383],{},[59,1384,1282],{},[16,1386,1387],{},[650,1388],{"alt":1389,"src":1390},"PlcTask properties window showing the Create symbols checkbox enabled","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fcreate-symbol.png",[1224,1392,1394],{"id":1393},"build-and-activate","Build and Activate",[472,1396,1397,1404],{"start":566},[56,1398,1399,1400,1403],{},"Press ",[59,1401,1402],{},"Ctrl+Shift+B"," to build the project. Check the output window for any errors before continuing.",[56,1405,1406,1407],{},"Right click the PLC instance in Solution Explorer and select ",[59,1408,1409],{},"Login",[328,1411,1412],{},[16,1413,1414,1416,1417,285],{},[59,1415,830],{}," If Login is not visible in the right click menu, find it in the top menu bar under ",[59,1418,1419],{},"PLC > Login",[472,1421,1422,1429],{"start":578},[56,1423,1424,1425,1428],{},"When TwinCAT prompts you to create the application on port 851, click ",[59,1426,1427],{},"Yes",". Do not skip this step or change the port.",[56,1430,1399,1431,1434],{},[59,1432,1433],{},"F5"," to start the PLC",[16,1436,1437],{},"The TwinCAT system tray icon must be green before you proceed. A blue icon means the runtime is not running and ADS connections will fail.",[16,1439,1440,1441,1444,1445,1447,1448,1450,1451,285],{},"Your test PLC is now running. Go back to the ",[105,1442,377],{"href":1443},"#configuring-ads-routes"," section and continue from there. The variable paths you will use throughout this guide are ",[349,1446,916],{},", ",[349,1449,982],{},", and ",[349,1452,1060],{},[26,1454,1456],{"id":1455},"conclusion","Conclusion",[16,1458,1459],{},"You now have a working ADS connection between FlowFuse and TwinCAT, reading variables on demand, subscribing to live changes, and writing values back to the PLC. But this is just the starting point.",[16,1461,1462,1463,1465],{},"This guide covered the core nodes to get you connected and working. The ",[349,1464,632],{}," package includes several other nodes worth exploring on your own, and future articles will cover more advanced use cases in depth.",[16,1467,1468],{},"With FlowFuse you can take this further. Build real-time dashboards that visualize live PLC data, connect TwinCAT to other systems like databases, ERP, or cloud platforms, set up alerts when variables go out of range, and create operator interfaces that let your team interact with the machine from anywhere. All of it built on the same connection you just configured, without writing a single line of custom integration code.",[16,1470,1471,1472,285],{},"Beckhoff TwinCAT ADS is one of many PLCs FlowFuse connects to the modern industrial stack. For Siemens, Allen-Bradley, Omron, Modbus, OPC UA, and more, see the ",[105,1473,1475],{"href":1474},"\u002Flanding\u002Fplc\u002F","FlowFuse PLC integration overview",[1477,1478,1479],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":230,"searchDepth":231,"depth":231,"links":1481},[1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1499],{"id":288,"depth":234,"text":289},{"id":340,"depth":234,"text":341},{"id":376,"depth":234,"text":377},{"id":607,"depth":234,"text":608},{"id":656,"depth":234,"text":657},{"id":869,"depth":234,"text":870},{"id":957,"depth":234,"text":958},{"id":1036,"depth":234,"text":1037},{"id":1132,"depth":234,"text":1133},{"id":1219,"depth":234,"text":336,"children":1492},[1493,1494,1495,1496,1497,1498],{"id":1226,"depth":507,"text":1227},{"id":1251,"depth":507,"text":1252},{"id":1285,"depth":507,"text":1286},{"id":1305,"depth":507,"text":1306},{"id":1357,"depth":507,"text":1358},{"id":1393,"depth":507,"text":1394},{"id":1455,"depth":234,"text":1456},{"type":243,"title":1501,"description":1502},"Connect TwinCAT to the Rest of Your Stack","FlowFuse makes it simple to take live PLC data further, dashboards, databases, ERP, cloud platforms, and alerts, all without custom integration code.","2026-03-13","Learn how to connect Beckhoff TwinCAT to FlowFuse using ADS. This guide covers AMS routing, TwinCAT software PLC setup, and reading and writing PLC variables with node-red-contrib-ads-client.","\u002Fblog\u002F2026\u002F03\u002Fimages\u002Fbackoff-twincat.png","2026-06-19",{"excerpt":1508},{"type":13,"value":1509},[1510],[16,1511,274],{},"\u002Fblog\u002F2026\u002F03\u002Fhow-to-connect-to-twincat-using-ads",{"title":268,"description":1504},{"loc":1512},"blog\u002F2026\u002F03\u002Fhow-to-connect-to-twincat-using-ads","Read and write TwinCAT PLC variables from FlowFuse using the ADS protocol, no additional licensing required.",[1518,263],"flowfuse","chQ3hbtHamZswFN5QOAEx7AQtWDIfzwt0APVEo74oQA",{"id":1521,"title":1522,"authors":1523,"body":1524,"cta":3,"date":1961,"description":1962,"extension":248,"image":1963,"lastUpdated":3,"meta":1964,"navigation":255,"path":1975,"seo":1976,"sitemap":1977,"stem":1978,"subtitle":1979,"tags":1980,"tldr":1981,"video":3,"__hash__":1982},"blog\u002Fblog\u002F2025\u002F12\u002Fwhat-is-plc.md","What Is a PLC (Programmable Logic Controller)? What It Does, How It Works, and Where It’s Used",[11],{"type":13,"value":1525,"toc":1940},[1526,1534,1543,1546,1555,1558,1562,1565,1568,1571,1574,1577,1581,1584,1593,1596,1599,1602,1609,1612,1621,1624,1628,1631,1634,1638,1644,1650,1656,1662,1666,1669,1695,1698,1701,1705,1714,1720,1726,1732,1735,1739,1742,1745,1748,1751,1755,1758,1762,1765,1771,1775,1778,1783,1787,1790,1795,1799,1802,1807,1811,1814,1818,1821,1824,1827,1830,1833,1837,1840,1843,1846,1849,1852,1855,1858,1862,1865,1868,1871,1874,1878,1900,1909,1912,1915,1921,1929,1937],[16,1527,1528],{},[1529,1530,1531],"em",{},[59,1532,1533],{},"A PLC (Programmable Logic Controller) is an industrial computer that continuously monitors sensors, executes control logic, and operates motors, valves, and equipment in real-time, serving as the reliable backbone of modern manufacturing and industrial automation.",[16,1535,1536,1537,1542],{},"On New Year's Day 1968, ",[105,1538,1541],{"href":1539,"rel":1540},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDick_Morley",[1240],"Dick Morley",", also known as the “Father of the PLC,” woke up with a brutal hangover and did what any reasonable engineer might do: he invented the future of manufacturing. That morning, nursing what he later described as \"a wicked headache,\" Morley wrote the complete specifications for the Programmable Logic Controller, a device that would replace entire relay-based control systems and become the invisible brain running modern industry.",[16,1544,1545],{},"Before that hungover epiphany, changing how a factory operated meant physically rewiring thousands of electromagnetic relays. General Motors was bleeding money, weeks of downtime and millions in labor costs every time they needed to retool a production line. Morley's Modicon 084 replaced 20,000 mechanical components with a single box that could be reprogrammed in hours.",[16,1547,1548,1549,1554],{},"Today, PLCs control everything from the jet engines on your flight to the insulin in your pharmacy. They manage power grids, traffic lights, water treatment plants, and semiconductor fabs. Eighty percent of industrial automation worldwide runs on PLCs. It's a ",[105,1550,1553],{"href":1551,"rel":1552},"https:\u002F\u002Fwww.mordorintelligence.com\u002Findustry-reports\u002Fprogrammable-logic-controller-plc-market",[1240],"$13 billion market",". And yet, most of us have never heard of them.",[16,1556,1557],{},"This article breaks down what PLCs actually are, traces their evolution from Morley's specs to modern systems, explains how they work under the hood, explores their real-world applications, and tackles the biggest challenge facing industrial automation today: getting PLCs from different manufacturers to actually talk to each other.",[26,1559,1561],{"id":1560},"what-is-a-plc-programmable-logic-controller","What is a PLC (Programmable Logic Controller) ?",[16,1563,1564],{},"A Programmable Logic Controller is an industrial computer built for one job: controlling machines and processes in real-time with rock-solid reliability. Unlike your laptop or the servers running cloud applications, PLCs thrive in environments that would kill standard computers, extreme temperatures, constant vibration, electrical noise, dust, and humidity.",[16,1566,1567],{},"The concept is elegant in its simplicity. A PLC continuously monitors inputs from sensors and switches, executes control logic from its stored program, and updates outputs that control motors, valves, lights, and equipment. This happens in a repeating \"scan cycle,\" typically thousands of times per second. Read inputs. Run logic. Update outputs. Repeat. Forever.",[16,1569,1570],{},"What sets PLCs apart isn't computing power, your phone vastly outperforms them. It's their deterministic behavior. When a PLC runs a program, it executes exactly the same way every single time. No operating system randomly running updates. No background processes stealing resources. No crashes. No reboots. In industries where failure means explosions, contaminated products, or fatalities, this predictability isn't a nice-to-have. It's survival.",[16,1572,1573],{},"The hardware reflects this zero-compromise approach. Industrial-grade components handle extreme temperatures and electrical interference. Power supplies absorb voltage swings that would fry consumer electronics. Input and output modules interface directly with industrial sensors and actuators at various voltages. The programming uses ladder logic and function blocks, visual languages mirroring the relay systems they replaced, designed for electricians and plant engineers rather than software developers.",[16,1575,1576],{},"This design has barely changed since Morley's 1968 specifications, and there's a reason: it works. When Siemens installs a PLC in a chemical plant, that system runs continuously for decades. When Rockwell Automation deploys controllers in automotive assembly, they execute millions of flawless cycles. Industrial automation doesn't embrace Silicon Valley's \"move fast and break things.\" The motto here is simpler: never break.",[26,1578,1580],{"id":1579},"history-of-plcs-from-relay-rooms-to-smart-controllers","History of PLCs: From Relay Rooms to Smart Controllers",[16,1582,1583],{},"Before PLCs, factories were wired nightmares. Control logic lived in walls of electromagnetic relays, thousands of mechanical switches wired together to define how a machine behaved. Changing a production process meant physically rewiring control panels. Every model change brought weeks of downtime, armies of electricians, and staggering costs. One wrong wire could halt an entire plant.",[16,1585,1586,1590],{},[650,1587],{"alt":1588,"dataZoomable":230,"src":1589},"Pre-PLC industrial relay control cabinet used in factories before programmable logic controllers replaced hard-wired relay logic\n","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Fpre-plc-relay-cabinet.jpg",[1529,1591,1592],{},"Pre-PLC industrial relay control cabinet used in factories before programmable logic controllers replaced hard-wired relay logic",[16,1594,1595],{},"By the late 1960s, this inflexibility was becoming fatal, especially for automotive manufacturers. General Motors was bleeding money on production line retooling. Meanwhile, a young engineer named Dick Morley was running a small consulting company called Bedford Associates, helping machine tool firms upgrade to solid-state controls. The work paid well, but it was monotonous, each project essentially the same as the last.",[16,1597,1598],{},"On New Year's Day 1968, nursing a hangover and running two weeks late on yet another proposal, Morley decided there had to be a better way. That morning, he wrote a complete specification for what he called a \"Programmable Controller\", a device that could replace relay logic, survive factory conditions, and be reprogrammed without rewiring. His specs were specific: no processing interrupts, direct memory mapping, rugged sealed design with heat sinks instead of fans, and a proprietary programming language (which would become ladder logic). One specification he'd later regret: he wanted it to operate slowly.",[16,1600,1601],{},"Morley took his memo to his team at Bedford Associates, Mike Greenberg, Jonas Landau, and Tom Boissevain. They got to work immediately, with one iron rule: never call it a computer. If Morley saw that word on any document, he'd throw it away. They built a rugged unit with metal fin heat sinks, completely sealed against factory environments. They named it the Model 084, Bedford's 84th project.",[16,1603,1604,1605,1608],{},"To commercialize the design, they needed investors. The team formed a new company in October 1968, calling it ",[59,1606,1607],{},"Modicon",", short for Modular Digital Controller. Morley was never technically an employee, but he ran engineering. The Model 084 shipped in 1969, followed quickly by the Model 184, which fixed issues found in the original.",[16,1610,1611],{},"General Motors heard about Modicon's work and placed a million-dollar order. In November 1969, GM's Hydramatic Division took delivery of the first batch. General Electric followed with their own million-dollar order, planning to rebrand and sell the controllers as OEM units. Within a year of Modicon's founding, the PLC had gone from hungover memo to production deployment at the world's largest automaker.",[16,1613,1614,1618],{},[650,1615],{"alt":1616,"dataZoomable":230,"src":1617},"PLC Pioneers Richard Morley, Tom Bossevain, George Schwenk and Jonas Landau\n","\u002Fblog\u002F2025\u002F12\u002Fimages\u002FFirst-modicon-084.png",[1529,1619,1620],{},"PLC Pioneers Richard Morley, Tom Bossevain, George Schwenk and Jonas Landau",[16,1622,1623],{},"Morley always called himself the \"Father\" of the PLC rather than its \"Inventor\", he knew others were working on similar solutions and believed the technology \"invented itself out of necessity.\" Bedford Associates eventually dissolved to avoid tax complications after Modicon's success. Modicon was later acquired and is now owned by Schneider Electric, which still occasionally uses the number 84 on products as a tribute.",[26,1625,1627],{"id":1626},"how-a-plc-works-scan-cycle-inputs-and-outputs","How a PLC Works: Scan Cycle, Inputs, and Outputs",[16,1629,1630],{},"Open a PLC cabinet on a factory floor and you'll find a metal box covered in wire terminals, mounted on a DIN rail, silently controlling millions of dollars of equipment. No monitor. No keyboard. No fan. Just a microprocessor executing the same loop it's been running since installation, sometimes for decades.",[16,1632,1633],{},"The entire operating model fits in one sentence: read sensors, run program, control outputs, repeat. That loop executes thousands of times per second with mechanical precision. It's not elegant. It's not exciting. But it's exactly what keeps production lines moving and chemical reactors stable.",[1224,1635,1637],{"id":1636},"whats-actually-inside-a-plc","What's Actually Inside a PLC",[16,1639,1640,1643],{},[59,1641,1642],{},"The CPU"," runs your control program. Modern units use industrial microprocessors, nothing exotic, just chips designed for temperature extremes and long-term reliability. They're slower than your phone but infinitely more predictable. The CPU executes code the same way every single time. No background processes. No operating system deciding to update drivers mid-cycle. Just pure determinism.",[16,1645,1646,1649],{},[59,1647,1648],{},"Input modules"," interface with sensors. A temperature probe sends a 4-20mA signal. A limit switch closes a 24V circuit. A pressure transducer outputs 1-5V DC. The input module converts these industrial signals into numbers the CPU can process, while providing electrical isolation to prevent ground loops and noise from corrupting data.",[16,1651,1652,1655],{},[59,1653,1654],{},"Output modules"," control physical equipment. The CPU decides a motor should run, and the output module closes a relay or sends a signal to a motor starter. It translates digital logic into the industrial voltages needed to activate contactors, solenoids, and valves. Like inputs, isolation protects the CPU from the electrical violence of switching inductive loads.",[16,1657,1658,1661],{},[59,1659,1660],{},"The power supply"," handles whatever garbage voltage the plant feeds it, sags during motor starts, spikes from switching, harmonics from variable frequency drives, and outputs clean DC. It's rated for abuse because industrial power is chaos.",[1224,1663,1665],{"id":1664},"the-scan-cycle","The Scan Cycle",[16,1667,1668],{},"Every PLC runs the same four-step loop:",[472,1670,1671,1677,1683,1689],{},[56,1672,1673,1676],{},[59,1674,1675],{},"Input scan",": Copy all sensor states into memory. This creates a snapshot, every input frozen at one moment in time.",[56,1678,1679,1682],{},[59,1680,1681],{},"Program execution",": Run the control logic from start to finish using that snapshot. If temperature > 250°F, open cooling valve. If part detected AND quality check passed, advance conveyor.",[56,1684,1685,1688],{},[59,1686,1687],{},"Output update",": Write all calculated outputs to physical modules. Motors start or stop. Valves open or close. But only after the entire program runs, no partial updates.",[56,1690,1691,1694],{},[59,1692,1693],{},"Housekeeping",": Handle communications, diagnostics, error checking. Then start over immediately.",[16,1696,1697],{},"The full cycle typically takes 1-50 milliseconds depending on program complexity. A 10ms scan cycle means the PLC makes 100 complete decisions per second. It's been doing this in some facilities since the 1980s.",[16,1699,1700],{},"This approach eliminates entire classes of software bugs. Inputs can't change mid-program. Outputs can't update while logic is executing. Race conditions don't exist. The program runs in strict sequential order, identically, every scan.",[1224,1702,1704],{"id":1703},"programming-languages","Programming Languages",[16,1706,1707,1708,1713],{},"PLCs don't use Python or C++. They use ",[105,1709,1712],{"href":1710,"rel":1711},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FIEC_61131-3",[1240],"IEC 61131-3"," languages designed for industrial electricians and control engineers.",[16,1715,1716,1719],{},[59,1717,1718],{},"Ladder Logic"," looks like relay wiring diagrams because it replaced relay logic. Horizontal lines represent power. Contacts (inputs) and coils (outputs) sit between them. An electrician who understood relay panels could program a PLC immediately. It's clunky for complex math but perfect for discrete control, if sensor A triggers and valve B is closed, start pump C.",[16,1721,1722,1725],{},[59,1723,1724],{},"Function Block Diagrams"," connect boxes representing timers, counters, math operations, and PID controllers. Data flows between blocks. It works well for process control where analog signals need continuous manipulation.",[16,1727,1728,1731],{},[59,1729,1730],{},"Structured Text"," handles complex calculations and algorithms. It looks like Pascal. Modern applications increasingly need it, ladder logic becomes unmanageable for sophisticated control strategies.",[16,1733,1734],{},"Each vendor implements these standards differently. Siemens uses TIA Portal. Rockwell has Studio 5000. Schneider offers Unity Pro. The languages are theoretically portable. The reality is vendor lock-in.",[1224,1736,1738],{"id":1737},"why-plcs-havent-changed","Why PLCs Haven't Changed",[16,1740,1741],{},"Your phone has more processing power than any PLC in existence. Yet every new factory, water treatment plant, and production line still installs PLCs. Why?",[16,1743,1744],{},"Because reliability beats performance in industrial automation. A PLC controlling a gas turbine or pharmaceutical batch doesn't need gigahertz processors or gigabytes of RAM. It needs to execute the same logic flawlessly for 20 years while operating at 140°F in an environment with electrical noise, vibration, and dust.",[16,1746,1747],{},"Consumer computing optimizes for speed and features. Industrial computing optimizes for never failing. Ever. The scan cycle, the isolated I\u002FO, the deterministic execution, these aren't limitations. They're the exact solution the problem requires.",[16,1749,1750],{},"That's why Morley's 1968 architecture still dominates. Not because the industry is conservative or backwards. Because he solved the problem correctly the first time.",[26,1752,1754],{"id":1753},"types-of-plcs","Types of PLCs",[16,1756,1757],{},"Not all PLCs are created equal. Walk through a factory and you’ll see shoebox-sized controllers running a single machine right next to rack-mounted systems managing entire production lines. While they all execute the same basic scan cycle, the hardware differs dramatically based on what they control.",[1224,1759,1761],{"id":1760},"compact-plcs","Compact PLCs",[16,1763,1764],{},"Compact PLCs integrate the CPU, I\u002FO, and power supply into a single fixed unit. They typically handle 10–100 I\u002FO points, making them ideal for packaging machines, pump stations, and HVAC systems. They are simple, cost-effective, and quick to deploy. Some models allow limited expansion through add-on I\u002FO modules, but scalability is constrained. Once that limit is reached, upgrading to a modular PLC is usually required.",[16,1766,1767,1770],{},[59,1768,1769],{},"Examples:"," Siemens S7-1200, Rockwell Micro800, Schneider Modicon M221",[1224,1772,1774],{"id":1773},"modular-plcs","Modular PLCs",[16,1776,1777],{},"Modular PLCs separate the CPU from the I\u002FO modules, which are installed on expandable racks. Need hundreds of I\u002FO points? Add modules. Need motion control, high-speed counting, or specialized communications? There is a dedicated module. This flexibility makes modular PLCs the standard for complex automation such as automotive assembly, chemical processing, and large material-handling systems. Costs typically range from $10,000 to well into six figures depending on scale and redundancy.",[16,1779,1780,1782],{},[59,1781,1769],{}," Siemens S7-1500, Rockwell ControlLogix, Schneider Modicon M580",[1224,1784,1786],{"id":1785},"safety-plcs","Safety PLCs",[16,1788,1789],{},"Safety PLCs are designed to protect people and equipment. They control emergency stops, light curtains, safety interlocks, and other safety-critical functions using redundant processors and continuous self-diagnostics. Certified safety architectures achieve reliability levels as high as 10⁻⁸ failures per hour (SIL 3 \u002F PLe). In most systems, safety PLCs operate alongside standard PLCs: production logic runs on the normal controller, while the safety PLC can override everything instantly when a hazard is detected.",[16,1791,1792,1794],{},[59,1793,1769],{}," Pilz PNOZmulti, Siemens F-series, Rockwell GuardLogix",[1224,1796,1798],{"id":1797},"micro-plcs","Micro PLCs",[16,1800,1801],{},"Micro PLCs handle very small automation tasks, typically 8–20 I\u002FO points, such as a single conveyor, pump, or sorter. They usually cost between $100 and $500 and are common in car washes, vending machines, irrigation systems, and compact OEM equipment. Programming is often simplified and focused on basic control logic rather than advanced automation features.",[16,1803,1804,1806],{},[59,1805,1769],{}," Unitronics, AutomationDirect CLICK, IDEC SmartRelay",[1224,1808,1810],{"id":1809},"choosing-the-right-plc","Choosing the Right PLC",[16,1812,1813],{},"Selecting a PLC comes down to I\u002FO count, system complexity, safety requirements, and future expansion. Simple machines with fewer than 20 I\u002FO points are well served by micro or compact PLCs. Production lines with hundreds of I\u002FO points, motion control, or advanced networking typically require modular PLCs. Any application involving human safety must use a safety-rated controller, without exception. Most companies standardize on a single vendor, commonly Siemens or Rockwell, and stay with that ecosystem for decades, as switching platforms later is costly and disruptive.",[26,1815,1817],{"id":1816},"plc-hmi-and-scada-how-they-work-together","PLC, HMI, and SCADA: How They Work Together",[16,1819,1820],{},"A PLC executes control logic in milliseconds, but it doesn't have a screen. It can't show operators what's happening. It can't log historical data or send alerts. That's where HMIs and SCADA systems come in.",[16,1822,1823],{},"These three technologies form distinct layers in industrial automation. PLCs control equipment in real-time, reading sensors, running logic, operating actuators. HMIs (Human-Machine Interfaces) are the touchscreens mounted next to machines that display what the PLC is doing and let operators start equipment, adjust setpoints, and acknowledge alarms. The HMI sends commands to the PLC, which evaluates safety conditions and executes them. One HMI typically monitors one machine or production line section.",[16,1825,1826],{},"SCADA (Supervisory Control and Data Acquisition) operates at the facility level. While an HMI monitors one machine, SCADA monitors entire plants or distributed systems. It collects data from dozens or hundreds of PLCs, stores trends in databases, generates reports, and coordinates system-wide operations. A water utility might have 50 pump stations, each with a PLC. SCADA at the central control room polls all 50 continuously, displays system-wide status, and lets operators manage the entire network from one location.",[16,1828,1829],{},"In practice: PLCs sit in control cabinets executing control programs. HMIs sit next to machines for local operation. SCADA runs on servers in control rooms for facility-wide oversight. All three communicate constantly, when a PLC detects high temperature, the local HMI displays an alarm, SCADA logs it with a timestamp and sends alerts to maintenance.",[16,1831,1832],{},"This hierarchy only works if these systems can actually talk to each other. That's where industrial automation hits its biggest challenge: vendor lock-in and protocol fragmentation. Getting PLCs from different manufacturers to communicate with HMIs and SCADA systems requires protocol converters, middleware, and significant integration effort, a problem we'll tackle next.",[26,1834,1836],{"id":1835},"where-plcs-actually-run-real-world-applications","Where PLCs Actually Run: Real-World Applications",[16,1838,1839],{},"PLCs control processes where reliability isn't negotiable. They're not exciting. They're not visible. But they're running constantly in factories, utilities, and infrastructure, often for decades without replacement.",[16,1841,1842],{},"Automotive assembly lines use PLCs to coordinate welding robots, conveyors, and quality systems. A body shop might run 50+ PLCs managing hundreds of welds per vehicle. When manufacturers retool for new models, they reprogram the controllers instead of rewiring entire panels, exactly what GM needed in 1968.",[16,1844,1845],{},"Pharmaceutical production relies on PLCs for batch reactors where temperature and timing must stay within tight tolerances. Every parameter gets logged for regulatory compliance. If conditions drift outside specifications, the PLC flags the batch automatically. Food and beverage plants use them for mixing, cooking, and packaging lines. A bottling line coordinates filling, capping, labeling, and case packing, all controlled by PLCs running the same programs they've executed millions of times.",[16,1847,1848],{},"Water treatment plants use PLCs to manage pumps, chemical dosing, and filtration based on flow rates and quality sensors. These systems often run for 20-30 years, handling daily demand variations and responding to system changes automatically. Power substations rely on PLCs for load monitoring, breaker control, and grid coordination. When generation or demand shifts, controllers adjust in milliseconds to maintain stability.",[16,1850,1851],{},"Refineries and chemical plants use them in environments where control failures create safety hazards, managing temperatures, pressures, and emergency shutdown sequences. Distribution centers use PLCs to run conveyor networks, sorting systems, and automated storage. A package gets scanned, routed through the optimal path, and diverted to the correct lane, all coordinated by controllers managing thousands of decision points per hour.",[16,1853,1854],{},"Airport baggage systems are entirely PLC-controlled. Bags move from check-in through security screening to the correct carousel, sorted by destination and flight timing. Mining operations use PLCs for conveyors, crushers, and material separation running continuously with minimal supervision. The controllers monitor equipment health, adjust speeds based on material flow, and shut down automatically when sensors detect problems.",[16,1856,1857],{},"The common thread is long-term reliability in demanding environments. PLCs installed in the 1990s are still operating in many facilities. They execute the same control logic, respond to the same sensors, and drive the same equipment, scan after scan, year after year, exactly as designed.",[26,1859,1861],{"id":1860},"the-interoperability-problem-when-plcs-wont-talk","The Interoperability Problem: When PLCs Won't Talk",[16,1863,1864],{},"Dick Morley solved factory automation in 1968. But as PLC manufacturers raced to capture the market he created, they built incompatible proprietary ecosystems, and vendor lock-in became the industry's unintended legacy.",[16,1866,1867],{},"Every major PLC manufacturer built their own proprietary ecosystem. Siemens controllers speak different protocols than Rockwell. Schneider systems don't natively understand Mitsubishi. Walk into any facility and you'll find a mix of PLCs, legacy systems, new equipment, different vendors. They all need to exchange data. Temperature from the Siemens PLC needs to trigger an action on the Rockwell controller. Production counts need to feed from one system into another.",[16,1869,1870],{},"The traditional solution? Custom integration work. Hire specialized engineers. Write gateway applications. Deploy protocol converters. Maintain separate codebases for each connection. When something breaks, troubleshoot across multiple proprietary systems while production sits idle.",[16,1872,1873],{},"The cost isn't just technical debt. It's strategic paralysis. Companies stick with a single vendor not because they offer the best solution, but because switching is too painful.",[26,1875,1877],{"id":1876},"flowfuse-breaking-the-integration-barrier","FlowFuse: Breaking the Integration Barrier",[16,1879,1880,1882,1883,1887,1888,1893,1894,1899],{},[105,1881,284],{"href":283},", built on ",[105,1884,1886],{"href":1885},"\u002Fnode-red\u002F","Node-RED",", solves the protocol chaos that vendor lock-in created. Node-RED emerged from IBM in 2013, created by ",[105,1889,1892],{"href":1890,"rel":1891},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fnickoleary\u002F",[1240],"Nick O'Leary"," (now CTO of FlowFuse) and ",[105,1895,1898],{"href":1896,"rel":1897},"https:\u002F\u002Fgithub.com\u002Fdceejay",[1240],"Dave Conway-Jones"," as a visual programming tool for connecting devices and APIs, drag nodes onto a canvas, wire them together, deploy. The industrial community built protocol nodes for Modbus, Profinet, EtherNet\u002FIP, S7comm, OPC UA, and more. It became the universal translator for industrial systems.",[16,1901,1902,1906],{},[650,1903],{"alt":1904,"dataZoomable":230,"src":1905},"FlowFuse platform for industrial data integration connecting PLCs, Node-RED, and enterprise systems\n","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Fflowfuse-platform.png",[1529,1907,1908],{},"FlowFuse platform for industrial data integration connecting PLCs, Node-RED, and enterprise systems",[16,1910,1911],{},"A single Node-RED instance can simultaneously communicate with Siemens S7 PLCs, Rockwell ControlLogix systems, Modbus devices, MQTT brokers, and IT systems like databases, APIs, and cloud platforms. The data flows visually. Changes deploy instantly. No compilation. No downtime. It bridges the operational technology (OT) on the factory floor with information technology (IT) systems, connecting PLCs not just to each other, but to ERP systems, historians, dashboards, and analytics platforms.",[16,1913,1914],{},"FlowFuse adds the enterprise infrastructure: centralized management across hundreds of edge devices, version control and rollback, role-based access, audit logging, and security at every layer. Build one flow that reads from Siemens PLCs and deploy it to every facility. When something changes, update once and push the change everywhere. Edge instances run locally even if network connections drop.",[16,1916,1917,1920],{},[105,1918,1919],{"href":1474},"FlowFuse doesn't replace your PLCs. It connects them."," That Rockwell controller keeps running its proven logic. The Siemens system continues its scan cycle. What changes is the integration layer that lets isolated systems finally communicate.",[16,1922,1923,1924,1928],{},"A ",[105,1925,1927],{"href":1926},"\u002Fcustomer-stories\u002Fmanufacturing-digital-transformation\u002F","large US manufacturing company"," with over 10,000 employees uses FlowFuse to manage thousands of Node-RED instances deployed across global facilities. These instances collect data from sensors, PLCs, and cameras on production lines, enabling them to transition from paper-based operations to real-time data visibility. A team of five developers, former manufacturing engineers, not software specialists, built hundreds of applications using Node-RED's visual programming. FlowFuse now manages deployment to thousands of remote devices and maintains multiple versions across all instances, solving what had become an unmanageable tracking challenge as they scaled.",[16,1930,1931,1932,1936],{},"Start small. Node-RED is open source. Connect two different PLC brands as a proof of concept. FlowFuse scales from there, one production line, then more sites, running on-premises or in the cloud as needs dictate.\nWant to see how FlowFuse handles PLC integration in your environment? ",[105,1933,1935],{"href":1934},"\u002Fbook-demo\u002F","Book a demo"," with our team, we'll connect to your mixed-vendor systems and show you what's possible in under an hour.",[16,1938,1939],{},"Dick Morley's hungover epiphany gave us PLCs that could be reprogrammed without rewiring. FlowFuse extends that flexibility to integration, connecting different systems without vendor permission, finally breaking the proprietary barriers Morley never intended.",{"title":230,"searchDepth":231,"depth":231,"links":1941},[1942,1943,1944,1950,1957,1958,1959,1960],{"id":1560,"depth":234,"text":1561},{"id":1579,"depth":234,"text":1580},{"id":1626,"depth":234,"text":1627,"children":1945},[1946,1947,1948,1949],{"id":1636,"depth":507,"text":1637},{"id":1664,"depth":507,"text":1665},{"id":1703,"depth":507,"text":1704},{"id":1737,"depth":507,"text":1738},{"id":1753,"depth":234,"text":1754,"children":1951},[1952,1953,1954,1955,1956],{"id":1760,"depth":507,"text":1761},{"id":1773,"depth":507,"text":1774},{"id":1785,"depth":507,"text":1786},{"id":1797,"depth":507,"text":1798},{"id":1809,"depth":507,"text":1810},{"id":1816,"depth":234,"text":1817},{"id":1835,"depth":234,"text":1836},{"id":1860,"depth":234,"text":1861},{"id":1876,"depth":234,"text":1877},"2025-12-26","Discover what PLCs are, how they work, and why 80% of global manufacturing still runs on Dick Morley's 1968 hungover invention. Plus: solving vendor lock-in","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Fwhat-is-plc.png",{"lastUpdate":1965,"keywords":1966,"excerpt":1967},"2025-12-29","what is plc, programmable logic controller, history of plc, father of plc, plc inventor, plc communication,",{"type":13,"value":1968},[1969],[16,1970,1971],{},[1529,1972,1973],{},[59,1974,1533],{},"\u002Fblog\u002F2025\u002F12\u002Fwhat-is-plc",{"title":1522,"description":1962},{"loc":1975},"blog\u002F2025\u002F12\u002Fwhat-is-plc","How Dick Morley's New Year's Day Hangover Changed Manufacturing Forever",[1518,263],"A Programmable Logic Controller (PLC) is a rugged industrial computer that continuously reads sensor inputs, executes control logic, and operates motors, valves, and equipment in real-time with deterministic reliability forming the backbone of 80% of global industrial automation since Dick Morley's 1968 invention. Unlike general-purpose computers, PLCs are designed for decades of uninterrupted operation in extreme environments, and the biggest modern challenge is getting PLCs from different vendors to communicate with each other and with enterprise IT systems.","R3rmKzbzPdRBwgo9abKiFbg46f9ZAxeWwe_ix_Joz-4",{"id":1984,"title":1985,"authors":1986,"body":1987,"cta":3,"date":2694,"description":2695,"extension":248,"image":2696,"lastUpdated":1506,"meta":2697,"navigation":255,"path":2703,"seo":2704,"sitemap":2705,"stem":2706,"subtitle":2707,"tags":2708,"tldr":2709,"video":3,"__hash__":2710},"blog\u002Fblog\u002F2025\u002F12\u002Fread-s7-optimized-datablocks-flowfuse.md","How to Access Optimized Data Blocks in TIA Portal (S7-1200\u002F1500)",[11],{"type":13,"value":1988,"toc":2681},[1989,1992,1995,2002,2005,2009,2014,2025,2028,2033,2036,2039,2044,2051,2065,2068,2072,2075,2078,2081,2083,2086,2103,2107,2110,2129,2137,2164,2171,2175,2178,2183,2190,2195,2198,2218,2226,2234,2237,2241,2244,2249,2279,2287,2292,2295,2300,2303,2331,2339,2344,2355,2358,2362,2365,2399,2402,2406,2409,2479,2482,2486,2489,2551,2555,2558,2652,2655,2662,2666,2669,2672,2675],[16,1990,1991],{},"When working with Siemens S7-1200 and S7-1500 PLCs, you’ll notice that TIA Portal creates optimized data blocks by default. Unlike the classic S7-300\u002F400 controllers, optimized blocks do not use fixed memory offsets. Instead, the PLC compiler reorganizes the data internally for better performance and memory efficiency. This architectural change often creates confusion when trying to read PLC data from external systems.",[16,1993,1994],{},"FlowFuse simplifies this challenge by providing a modern way to connect OT and IT systems and build industrial applications using a low-code, drag-and-drop approach. However, reading optimized data blocks still requires a different access method than traditional S7 communication.",[16,1996,1997,1998,2001],{},"You can disable optimization in TIA Portal by unchecking the \"Optimized block access\" option in your data block properties. This gives you the old-style addressing where you can read data using fixed offsets like ",[349,1999,2000],{},"DB1.DBW0",". However, this approach has several drawbacks. Optimized blocks run faster, use less memory, and follow Siemens' current best practices. If you're working on existing projects with thousands of tags, converting everything to standard blocks isn't practical. Many companies also require optimized blocks as part of their coding standards.",[16,2003,2004],{},"This guide shows you how to read optimized data blocks directly without disabling optimization. You'll learn to use symbolic addressing, which is the proper way to access data from modern Siemens PLCs.",[26,2006,2008],{"id":2007},"why-reading-optimized-data-blocks-is-challenging","Why Reading Optimized Data Blocks Is Challenging",[16,2010,2011],{},[59,2012,2013],{},"The S7 Protocol Problem",[16,2015,2016,2017,2020,2021,2024],{},"Traditional S7 communication, which most Node-RED S7 nodes use, relies on absolute memory addresses. You read data by specifying exact locations like ",[349,2018,2019],{},"DB1,INT0"," (read integer at byte 0) or ",[349,2022,2023],{},"DB5,REAL10"," (read real at byte 10).",[16,2026,2027],{},"This worked fine with classic S7-300\u002F400 controllers where memory layout was predictable. If you declared an integer first in your data block, it always started at byte 0. Simple and reliable.",[16,2029,2030],{},[59,2031,2032],{},"What Optimization Breaks",[16,2034,2035],{},"Optimized data blocks rearrange variables for better performance and memory efficiency. The compiler groups variables by type, adds alignment padding, and reorders declarations. Your variable positions become unpredictable and can change with each recompile.",[16,2037,2038],{},"Example: You create variables Temperature (Real), Status (Bool), Pressure (Real), Alarm (Bool). Instead of sequential storage, the optimizer might group the two Real values together and pack Bools elsewhere. The Status boolean isn't at byte 4 anymore, it could be anywhere.",[16,2040,2041],{},[59,2042,2043],{},"Why S7 Nodes Fail",[16,2045,2046,2047,2050],{},"Node-RED packages like ",[349,2048,2049],{},"node-red-contrib-s7"," need exact memory addresses. With optimized blocks:",[53,2052,2053,2056,2059,2062],{},[56,2054,2055],{},"TIA Portal doesn't show you the actual memory layout",[56,2057,2058],{},"Offsets can't be reliably determined",[56,2060,2061],{},"Recompiling your PLC program silently breaks all your addresses",[56,2063,2064],{},"The S7 protocol has no way to read variables by name",[16,2066,2067],{},"You're stuck guessing at memory locations that keep changing.",[26,2069,2071],{"id":2070},"the-solution-opc-ua","The Solution: OPC UA",[16,2073,2074],{},"OPC UA reads variables by name, not memory address. Instead of asking \"what's at byte 10?\" it asks \"what's the value of Temperature_Sensor_01?\"",[16,2076,2077],{},"Siemens S7-1200 and S7-1500 PLCs have built-in OPC UA server. Activate it in TIA Portal, mark which variables to expose, and the PLC handles all memory mapping internally. FlowFuse connects and reads data by variable name, regardless of how the PLC organizes memory.",[16,2079,2080],{},"When you modify your data block or recompile, your flows keep working because they reference variable names, not memory locations that might shift.",[26,2082,289],{"id":288},[16,2084,2085],{},"Before you begin, make sure you have:",[53,2087,2088,2091,2094,2100],{},[56,2089,2090],{},"TIA Portal V13 or later, and you know how to download a program to your PLC",[56,2092,2093],{},"A Siemens S7-1200 or S7-1500 PLC with OPC UA server support",[56,2095,1923,2096,2099],{},[105,2097,2098],{"href":303},"FlowFuse Agent"," running on your edge device",[56,2101,2102],{},"The PLC and edge device connected to the same network",[26,2104,2106],{"id":2105},"step-1-activate-opc-ua-server-on-your-plc","Step 1: Activate OPC UA Server on Your PLC",[16,2108,2109],{},"First, you need to activate the OPC UA server that's built into your S7-1200\u002F1500 PLC.",[472,2111,2112,2115,2118,2124],{},[56,2113,2114],{},"Launch TIA Portal and open your project",[56,2116,2117],{},"In the project tree on the left, select your PLC and double-click it",[56,2119,2120,2121,2123],{},"Find ",[59,2122,152],{}," in the device properties (usually under General or Properties section)",[56,2125,1376,2126],{},[59,2127,2128],{},"Activate OPC UA Server",[16,2130,2131,2135],{},[650,2132],{"alt":2133,"dataZoomable":230,"src":2134},"Activate OPC UA server option in TIA Portal","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Fenable-opcua-server.png",[1529,2136,2133],{},[472,2138,2139,2149,2158],{"start":518},[56,2140,2141,2142,989,2145,2148],{},"Set ",[59,2143,2144],{},"Port",[349,2146,2147],{},"4840"," (the standard OPC UA port)",[56,2150,2141,2151,989,2154,2157],{},[59,2152,2153],{},"Security Policy",[59,2155,2156],{},"None"," (for testing only)",[56,2159,2160,2161,285],{},"Enable ",[59,2162,2163],{},"Guest authentication",[328,2165,2166],{},[16,2167,2168],{},[1529,2169,2170],{},"Note that we've disabled security entirely in steps 6-7 to get you up and running quickly. This is fine for learning and testing, but don't leave it this way. Before moving to production, configure proper authentication with certificates and user credentials. Get the communication working first, then secure it.",[26,2172,2174],{"id":2173},"step-2-add-opc-ua-server-interface","Step 2: Add OPC UA Server Interface",[16,2176,2177],{},"Before exposing variables, you need to create an OPC UA server interface in your PLC configuration.",[16,2179,2180],{},[59,2181,2182],{},"For S7-1500 PLCs (firmware V2.5 or higher):",[16,2184,2185,2186,2189],{},"If you're using an S7-1500 PLC with firmware version 2.5 or higher, you have the option to enable the standard SIMATIC server interface. Simply check ",[59,2187,2188],{},"Enable standard SIMATIC server interface"," in the OPC UA settings. This automatically makes all PLC tags that are marked as accessible available through OPC UA.",[16,2191,2192],{},[59,2193,2194],{},"For S7-1200 PLCs (or manual configuration for S7-1500):",[16,2196,2197],{},"For S7-1200 PLCs, you must manually create a server interface and add the tags you want to expose:",[472,2199,2200,2207,2213],{},[56,2201,2202,2203,2206],{},"In TIA Portal, navigate to ",[59,2204,2205],{},"OPC UA communication"," in the project tree",[56,2208,2209,2210],{},"Right-click on ",[59,2211,2212],{},"Server interfaces",[56,2214,1265,2215],{},[59,2216,2217],{},"Add new server interface",[16,2219,2220,2224],{},[650,2221],{"alt":2222,"dataZoomable":230,"src":2223},"Adding OPC UA server interface in TIA Portal","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Fadd-server-interface.png",[1529,2225,2222],{},[472,2227,2228,2231],{"start":231},[56,2229,2230],{},"Leave the default settings and click OK",[56,2232,2233],{},"The server interface will be created (you can rename it if needed)",[16,2235,2236],{},"Now this interface needs to know which data blocks to expose.",[26,2238,2240],{"id":2239},"step-3-expose-your-data-block-variables","Step 3: Expose Your Data Block Variables",[16,2242,2243],{},"For OPC UA to access your data blocks, you need to mark them as accessible.",[16,2245,2246],{},[59,2247,2248],{},"First, enable OPC UA access on your data blocks (required for all methods):",[472,2250,2251,2254,2257,2262,2267,2275],{},[56,2252,2253],{},"Open your data block in TIA Portal",[56,2255,2256],{},"Right-click on the data block name in the project tree",[56,2258,1265,2259],{},[59,2260,2261],{},"Properties",[56,2263,622,2264,626],{},[59,2265,2266],{},"Attributes",[56,2268,1376,2269,811,2272],{},[59,2270,2271],{},"Accessible from HMI\u002FOPC UA",[59,2273,2274],{},"Optimized Block Access",[56,2276,635,2277],{},[59,2278,1282],{},[16,2280,2281,2285],{},[650,2282],{"alt":2283,"dataZoomable":230,"src":2284},"Attribute settings for optimized and OPC UA accessible data blocks","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Foptimized-db-and-accessbile-via-opcua-option.png",[1529,2286,2283],{},[16,2288,2289],{},[59,2290,2291],{},"If using S7-1500 with standard SIMATIC server interface:",[16,2293,2294],{},"You're done. All variables in data blocks marked as accessible are now automatically available through OPC UA.",[16,2296,2297],{},[59,2298,2299],{},"If using manual server interface (S7-1200 or S7-1500):",[16,2301,2302],{},"You need one more step to add specific variables to your server interface:",[472,2304,2305,2310,2313,2320],{},[56,2306,2307,2308],{},"In the project tree, expand ",[59,2309,2205],{},[56,2311,2312],{},"Expand your server interface",[56,2314,2315,2316,2319],{},"Drag and drop variables from the ",[59,2317,2318],{},"OPC UA elements"," panel (on the right) into your server interface table",[56,2321,2322,2323,2326,2327,2330],{},"Alternatively, right-click ",[59,2324,2325],{},"Variables"," and select ",[59,2328,2329],{},"Add new variable",", then browse to select them",[16,2332,2333,2337],{},[650,2334],{"alt":2335,"dataZoomable":230,"src":2336},"Tags added inside OPC UA server interface","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Ftags-added-in-the-server-interface.png",[1529,2338,2335],{},[16,2340,2341],{},[59,2342,2343],{},"Compile and download:",[472,2345,2346,2352],{"start":518},[56,2347,635,2348,2351],{},[59,2349,2350],{},"Compile"," in TIA Portal",[56,2353,2354],{},"Download the program to your PLC",[16,2356,2357],{},"Your OPC UA server is now running with the exposed variables ready for access.",[26,2359,2361],{"id":2360},"step-4-install-opc-ua-client-in-flowfuse","Step 4: Install OPC UA Client in FlowFuse",[16,2363,2364],{},"Now switch to your FlowFuse instance to set up the connection to your PLC.",[472,2366,2367,2370,2373,2378,2382,2388,2393,2396],{},[56,2368,2369],{},"Open your FlowFuse editor",[56,2371,2372],{},"Click the menu icon (three horizontal lines, top right)",[56,2374,1265,2375],{},[59,2376,2377],{},"Manage palette",[56,2379,622,2380,626],{},[59,2381,625],{},[56,2383,2384,2385],{},"In the search box, type ",[349,2386,2387],{},"node-red-contrib-opcua",[56,2389,2390,2391],{},"Find the package in the results and click ",[59,2392,625],{},[56,2394,2395],{},"Confirm the installation when prompted",[56,2397,2398],{},"Close the palette manager",[16,2400,2401],{},"The OPC UA nodes will now appear in your node palette on the left side under the \"opcua\" category.",[26,2403,2405],{"id":2404},"step-5-configure-opc-ua-connection","Step 5: Configure OPC UA Connection",[16,2407,2408],{},"Create a new flow to connect to your PLC and read data.",[472,2410,2411,2417,2420,2427,2446,2452,2459,2469,2474],{},[56,2412,878,2413,2416],{},[59,2414,2415],{},"OpcUa-Client"," node onto your canvas",[56,2418,2419],{},"Double-click it to open the configuration",[56,2421,2422,2423,2426],{},"Click the pencil icon next to ",[59,2424,2425],{},"Endpoint"," to add a new connection",[56,2428,2429,2430,2433],{},"Enter the endpoint URL: ",[349,2431,2432],{},"opc.tcp:\u002F\u002F[YOUR_PLC_IP]:4840",[53,2434,2435],{},[56,2436,2437,2438,2441,2442,2445],{},"Replace ",[349,2439,2440],{},"[YOUR_PLC_IP]"," with your actual PLC IP address (e.g., ",[349,2443,2444],{},"opc.tcp:\u002F\u002F192.168.1.10:4840",")",[56,2447,2141,2448,989,2450],{},[59,2449,2153],{},[59,2451,2156],{},[56,2453,2141,2454,989,2457],{},[59,2455,2456],{},"Security Mode",[59,2458,2156],{},[56,2460,2461,2462,2465,2466],{},"Under ",[59,2463,2464],{},"Authentication",", select ",[59,2467,2468],{},"Anonymous",[56,2470,635,2471,2473],{},[59,2472,842],{}," to save the endpoint",[56,2475,635,2476,2478],{},[59,2477,848],{}," to close the node configuration",[16,2480,2481],{},"Your OPC UA client is now configured to connect to your PLC.",[26,2483,2485],{"id":2484},"step-6-browse-available-variables","Step 6: Browse Available Variables",[16,2487,2488],{},"Now it's time to discover what's actually available on your PLC. Think of this like opening a file explorer to see what's inside.",[472,2490,2491,2496,2501,2506,2509,2515,2520,2530,2534,2539,2542,2548],{},[56,2492,878,2493,2416],{},[59,2494,2495],{},"Inject",[56,2497,878,2498,671],{},[59,2499,2500],{},"OpcUa-Browser",[56,2502,932,2503,671],{},[59,2504,2505],{},"Debug",[56,2507,2508],{},"Connect the Inject node to the OpcUa-Browser node, then connect the OpcUa-Browser node to the Debug node",[56,2510,2511,2512,2514],{},"Double-click the ",[59,2513,2500],{}," node to open its configuration",[56,2516,688,2517,2519],{},[59,2518,2425],{}," dropdown, select the connection you created in Step 5",[56,2521,2522,2523,2526,2527],{},"Leave the ",[59,2524,2525],{},"Action"," field set to ",[59,2528,2529],{},"browse",[56,2531,635,2532],{},[59,2533,848],{},[56,2535,635,2536,2538],{},[59,2537,853],{}," in the top-right corner",[56,2540,2541],{},"Click the inject node button",[56,2543,2544,2545,2547],{},"Open the ",[59,2546,2505],{}," panel on the right side",[56,2549,2550],{},"You'll see a structured tree showing everything your PLC is sharing",[26,2552,2554],{"id":2553},"step-7-read-your-first-variable","Step 7: Read Your First Variable",[16,2556,2557],{},"Let's prove this actually works by reading real data from your PLC.",[472,2559,2560,2564,2567,2577,2583,2592,2596,2600,2603,2608,2615,2619,2623,2626,2632,2636,2639,2643,2646],{},[56,2561,878,2562,2416],{},[59,2563,2495],{},[56,2565,2566],{},"Double-click the Inject node to configure it",[56,2568,2569,2570,2573,2574],{},"Change ",[59,2571,2572],{},"Repeat"," from \"none\" to ",[59,2575,2576],{},"interval",[56,2578,2579,2580],{},"Set it to repeat ",[59,2581,2582],{},"every 5 seconds",[56,2584,688,2585,2588,2589,2445],{},[59,2586,2587],{},"Topic"," field, enter the NodeId you copied (e.g., ",[349,2590,2591],{},"ns=3;s=\"Demo_Datablock\".\"Temperature\"",[56,2593,635,2594],{},[59,2595,848],{},[56,2597,878,2598,671],{},[59,2599,2415],{},[56,2601,2602],{},"Double-click the OpcUa-Client node to open its configuration",[56,2604,2605,2606,902],{},"Select your endpoint from the ",[59,2607,2425],{},[56,2609,2569,2610,989,2612],{},[59,2611,2525],{},[59,2613,2614],{},"read",[56,2616,635,2617],{},[59,2618,848],{},[56,2620,932,2621,671],{},[59,2622,2505],{},[56,2624,2625],{},"Double-click the Debug node",[56,2627,2628,2629],{},"Change the output to ",[59,2630,2631],{},"complete msg object",[56,2633,635,2634],{},[59,2635,848],{},[56,2637,2638],{},"Connect the Inject node to the OpcUa-Client node, then connect the OpcUa-Client node to the Debug node",[56,2640,635,2641],{},[59,2642,853],{},[56,2644,2645],{},"Open the Debug panel on the right side",[56,2647,2648,2649],{},"You'll see messages appearing every 5 seconds with your variable's value in ",[349,2650,2651],{},"msg.payload",[16,2653,2654],{},"Try changing the value in your PLC through TIA Portal and watch the updates appear in FlowFuse. No memory addresses, no offset calculations, just the variable name.",[16,2656,2657,2658,285],{},"To explore more OPC UA capabilities like subscribing to value changes, writing data back to your PLC, and working with complex data types, check out our ",[105,2659,2661],{"href":2660},"\u002Fblog\u002F2025\u002F07\u002Freading-and-writing-plc-data-using-opc-ua\u002F","article",[26,2663,2665],{"id":2664},"scale-your-industrial-applications-with-flowfuse","Scale Your Industrial Applications with FlowFuse",[16,2667,2668],{},"You've successfully read data from your Siemens PLC, but FlowFuse does much more than connect to a single device. The platform helps you build complete industrial applications that connect to any equipment, collect and transform data from across your factory floor, visualize it in real-time dashboards, and take automated actions based on what's happening in your operation.",[16,2670,2671],{},"FlowFuse makes deployment and management simple, even at scale. Develop your application once, then deploy it to thousands of edge devices across multiple facilities. Manage all your instances from one central platform, push updates, monitor performance, and troubleshoot remotely without visiting each site. Built-in security features protect your industrial data, while horizontal and vertical scaling ensures your applications grow with your business needs.",[16,2673,2674],{},"Whether you're building a predictive maintenance system, a production monitoring dashboard, or a complete MES solution, FlowFuse provides the unified platform to connect, collect, transform, visualize, and act on your industrial data.",[16,2676,2677,2678,2680],{},"Ready to scale beyond a single PLC? ",[105,2679,1935],{"href":1934}," to see how FlowFuse can transform your industrial operations.",{"title":230,"searchDepth":231,"depth":231,"links":2682},[2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693],{"id":2007,"depth":234,"text":2008},{"id":2070,"depth":234,"text":2071},{"id":288,"depth":234,"text":289},{"id":2105,"depth":234,"text":2106},{"id":2173,"depth":234,"text":2174},{"id":2239,"depth":234,"text":2240},{"id":2360,"depth":234,"text":2361},{"id":2404,"depth":234,"text":2405},{"id":2484,"depth":234,"text":2485},{"id":2553,"depth":234,"text":2554},{"id":2664,"depth":234,"text":2665},"2025-12-04","Learn how to read Siemens S7-1200\u002F1500 optimized data blocks using OPC UA and FlowFuse. Step-by-step guide with symbolic addressing for reliable PLC integration.","\u002Fblog\u002F2025\u002F12\u002Fimages\u002Freading-s7-optimize-data-block.png",{"keywords":2698,"excerpt":2699},"Siemens S7-1200, Siemens S7-1500, optimized data blocks, TIA Portal, OPC UA, symbolic addressing, FlowFuse, Node-RED, PLC data access, S7 protocol, OPC UA client, industrial automation, PLC integration, S7-1200 OPC UA, S7-1500 OPC UA, Siemens PLC communication, reading optimized DB",{"type":13,"value":2700},[2701],[16,2702,1991],{},"\u002Fblog\u002F2025\u002F12\u002Fread-s7-optimized-datablocks-flowfuse",{"title":1985,"description":2695},{"loc":2703},"blog\u002F2025\u002F12\u002Fread-s7-optimized-datablocks-flowfuse","Use OPC UA to read optimized data blocks by name instead of fighting with memory addresses",[1518,263],"Siemens S7-1200 and S7-1500 PLCs use optimized data blocks by default, which rearrange variable memory layouts at compile time making traditional S7 protocol nodes that rely on fixed byte offsets unreliable. The solution is OPC UA, which reads variables by symbolic name rather than memory address; this guide shows step-by-step how to enable the OPC UA server in TIA Portal and read optimized data block variables reliably by name.","S1-ONm9jaMBx7vM-JUTeo2aZeCHxhQdjlFALLH1HXFQ",{"id":2712,"title":2713,"authors":2714,"body":2715,"cta":3,"date":3991,"description":3992,"extension":248,"image":3993,"lastUpdated":246,"meta":3994,"navigation":255,"path":4000,"seo":4001,"sitemap":4002,"stem":4003,"subtitle":4004,"tags":4005,"tldr":4006,"video":3,"__hash__":4007},"blog\u002Fblog\u002F2025\u002F11\u002Fstore-and-forward-edge-data-buffering.md","Store-and-Forward at the Edge: Buffering Production Data During Network Outages",[11],{"type":13,"value":2716,"toc":3972},[2717,2720,2723,2726,2729,2735,2739,2742,2745,2890,2893,2897,2900,2903,2905,2908,2928,2932,2935,2938,2941,2947,2951,2954,2957,2978,2986,2995,3037,3044,3059,3062,3066,3069,3090,3098,3106,3158,3166,3185,3200,3207,3214,3218,3221,3224,3245,3253,3286,3294,3300,3309,3340,3348,3372,3380,3404,3412,3420,3423,3427,3430,3435,3458,3483,3528,3536,3557,3565,3578,3581,3585,3588,3592,3617,3625,3639,3647,3664,3672,3688,3707,3712,3716,3724,3731,3762,3770,3786,3806,3819,3839,3846,3849,3876,3884,3944,3946,3949,3952,3955,3958,3965,3970],[16,2718,2719],{},"Network outages happen. A fiber cut, a switch failure, or infrastructure maintenance can take your connectivity offline without warning. When it does, your PLCs continue operating normally, they don't wait for the network to recover.",[16,2721,2722],{},"The problem is that all the data they generate during that outage has nowhere to go. Production metrics, quality measurements, and alarm events accumulate with no path to your historian or cloud platform. When connectivity returns, you're left with gaps in your operational records. Those gaps create real problems: incomplete batch records for quality audits, missing data for troubleshooting production issues, and compliance documentation that doesn't hold up under review.",[16,2724,2725],{},"Store-and-forward solves this. This article walks through building a store-and-forward system with FlowFuse that maintains complete data continuity during network failures.",[16,2727,2728],{},"Below is the demo video where I show how production data can be lost without buffering, and how buffering prevents that from happening.",[950,2730],{"videoid":2731,"params":2732,"style":2733,"title":2734},"J1gDj6S-ijI","rel=0","margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;","YouTube video player",[26,2736,2738],{"id":2737},"what-is-store-and-forward","What is Store-and-Forward?",[16,2740,2741],{},"Store-and-forward is a pattern where data is saved locally before transmission, then forwarded when network connectivity is available. Your edge device writes every data point to local SQLite storage first. If the network is up, the data transmits to your destination, MQTT broker, historian, cloud platform, or database. If the network is down, the data stays in storage until connectivity returns.",[16,2743,2744],{},"The edge device operates in three states. During normal operation, data writes to the buffer and forwards successfully, the buffer stays near-empty. During a network outage, data continues writing to the buffer but cannot forward, the buffer grows. When connectivity returns, the device forwards the buffered backlog in chronological order while continuing to collect new data, the buffer drains back to empty.",[485,2746,2750],{"className":2747,"code":2748,"language":2749,"meta":230,"style":230},"language-mermaid shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","flowchart TD\n    Source[PLC \u002F Sensor]\n    Destination[Cloud \u002F Broker \u002F Server]\n\n    Source --> Start[Data Arrives at Edge]\n    Start --> Save[Store in Local Buffer]\n    Save --> Check{Network Available?}\n\n    Check -->|Connected| Send[Send Data]\n    Send --> Destination\n    Destination --> Clear[Remove Data from Buffer]\n\n    Check -->|Disconnected| Wait[Keep Data in Buffer]\n    Wait --> Retry[Retry Until Network Restored]\n    Retry --> Check\n\n    %% Styling (consistent theme)\n    style Source fill:#3B82F6,color:#fff\n    style Start fill:#3B82F6,color:#fff\n    style Save fill:#818CF8,color:#fff\n    style Check fill:#6366F1,color:#fff\n    style Send fill:#60A5FA,color:#fff\n    style Destination fill:#60A5FA,color:#fff\n    style Clear fill:#93C5FD,color:#000\n    style Wait fill:#A5B4FC,color:#fff\n    style Retry fill:#BFDBFE,color:#000\n","mermaid",[349,2751,2752,2757,2762,2767,2772,2777,2782,2787,2791,2796,2801,2806,2810,2815,2820,2825,2830,2836,2842,2848,2854,2860,2866,2872,2878,2884],{"__ignoreMap":230},[493,2753,2754],{"class":495,"line":496},[493,2755,2756],{},"flowchart TD\n",[493,2758,2759],{"class":495,"line":234},[493,2760,2761],{},"    Source[PLC \u002F Sensor]\n",[493,2763,2764],{"class":495,"line":507},[493,2765,2766],{},"    Destination[Cloud \u002F Broker \u002F Server]\n",[493,2768,2769],{"class":495,"line":231},[493,2770,2771],{"emptyLinePlaceholder":255},"\n",[493,2773,2774],{"class":495,"line":518},[493,2775,2776],{},"    Source --> Start[Data Arrives at Edge]\n",[493,2778,2779],{"class":495,"line":524},[493,2780,2781],{},"    Start --> Save[Store in Local Buffer]\n",[493,2783,2784],{"class":495,"line":530},[493,2785,2786],{},"    Save --> Check{Network Available?}\n",[493,2788,2789],{"class":495,"line":536},[493,2790,2771],{"emptyLinePlaceholder":255},[493,2792,2793],{"class":495,"line":542},[493,2794,2795],{},"    Check -->|Connected| Send[Send Data]\n",[493,2797,2798],{"class":495,"line":548},[493,2799,2800],{},"    Send --> Destination\n",[493,2802,2803],{"class":495,"line":554},[493,2804,2805],{},"    Destination --> Clear[Remove Data from Buffer]\n",[493,2807,2808],{"class":495,"line":560},[493,2809,2771],{"emptyLinePlaceholder":255},[493,2811,2812],{"class":495,"line":566},[493,2813,2814],{},"    Check -->|Disconnected| Wait[Keep Data in Buffer]\n",[493,2816,2817],{"class":495,"line":572},[493,2818,2819],{},"    Wait --> Retry[Retry Until Network Restored]\n",[493,2821,2822],{"class":495,"line":578},[493,2823,2824],{},"    Retry --> Check\n",[493,2826,2828],{"class":495,"line":2827},16,[493,2829,2771],{"emptyLinePlaceholder":255},[493,2831,2833],{"class":495,"line":2832},17,[493,2834,2835],{},"    %% Styling (consistent theme)\n",[493,2837,2839],{"class":495,"line":2838},18,[493,2840,2841],{},"    style Source fill:#3B82F6,color:#fff\n",[493,2843,2845],{"class":495,"line":2844},19,[493,2846,2847],{},"    style Start fill:#3B82F6,color:#fff\n",[493,2849,2851],{"class":495,"line":2850},20,[493,2852,2853],{},"    style Save fill:#818CF8,color:#fff\n",[493,2855,2857],{"class":495,"line":2856},21,[493,2858,2859],{},"    style Check fill:#6366F1,color:#fff\n",[493,2861,2863],{"class":495,"line":2862},22,[493,2864,2865],{},"    style Send fill:#60A5FA,color:#fff\n",[493,2867,2869],{"class":495,"line":2868},23,[493,2870,2871],{},"    style Destination fill:#60A5FA,color:#fff\n",[493,2873,2875],{"class":495,"line":2874},24,[493,2876,2877],{},"    style Clear fill:#93C5FD,color:#000\n",[493,2879,2881],{"class":495,"line":2880},25,[493,2882,2883],{},"    style Wait fill:#A5B4FC,color:#fff\n",[493,2885,2887],{"class":495,"line":2886},26,[493,2888,2889],{},"    style Retry fill:#BFDBFE,color:#000\n",[16,2891,2892],{},"This solves the core problem in industrial data collection: network failures creating gaps in your time-series data. A four-hour outage would normally mean four hours of missing production data. With store-and-forward, that same outage causes zero data loss. Your destination system receives complete chronological data with only a delivery delay.",[26,2894,2896],{"id":2895},"getting-started","Getting Started",[16,2898,2899],{},"Let's build a store-and-forward system to protect your data during network outages.",[16,2901,2902],{},"We'll approach this in six steps: establish a connection to collect data, set up a local buffer to temporarily store that data, write incoming data to the buffer, monitor network connectivity status, create forwarding logic to transmit buffered data when connectivity returns, and finally add error handling and buffer management to ensure reliable operation.",[1224,2904,289],{"id":288},[16,2906,2907],{},"You'll need the following before implementing store-and-forward:",[53,2909,2910,2916,2922],{},[56,2911,2912,2915],{},[59,2913,2914],{},"Edge Device Running FlowFuse Agent",": A running FlowFuse instance deployed on your edge hardware or gateway device.",[56,2917,2918,2921],{},[59,2919,2920],{},"node-red-node-sqlite",": SQLite node for local data storage.",[56,2923,2924,2927],{},[59,2925,2926],{},"node-red-contrib-ping",": Ping node for connectivity monitoring.",[1224,2929,2931],{"id":2930},"step-1-set-up-data-collection","Step 1: Set Up Data Collection",[16,2933,2934],{},"Data collection is the foundation of store-and-forward. Your edge device needs reliable connectivity to your data sources before you can buffer and forward their data.",[16,2936,2937],{},"FlowFuse handles this through Node-RED's 5,000+ community nodes, which support virtually every industrial protocol and interface, Modbus, OPC UA, MQTT, Ethernet\u002FIP, GPIO pins, serial connections, and more. You collect data from your sources, transform it into the format you need, and prepare it for buffering.",[16,2939,2940],{},"For this guide, we'll assume you already have data flowing into FlowFuse. The store-and-forward pattern works the same regardless of which data sources or protocols you're using.",[16,2942,2943,2944,285],{},"For more information on how FlowFuse can help you connect, collect, transform, and contextualize your data, and how it simplifies deployment, management, scaling, and security with enterprise features for production environments, ",[105,2945,2946],{"href":1934},"book a demo",[1224,2948,2950],{"id":2949},"step-2-implement-sqlite-buffering","Step 2: Implement SQLite Buffering",[16,2952,2953],{},"SQLite provides the persistent storage layer for your store-and-forward buffer. It's lightweight, requires no separate database server, and handles the write volumes typical of industrial data collection without issue.",[16,2955,2956],{},"Follow these steps to set up your SQLite buffer:",[472,2958,2959,2966],{},[56,2960,2961,2962,2965],{},"Drag the ",[59,2963,2964],{},"sqlite"," node from the palette onto your workspace.",[56,2967,2968,2969,2465,2971,2974,2975,2977],{},"Double-click the node to open its configuration panel. Click the pencil icon next to the Database field to create a new database configuration. Give it a name like ",[59,2970,2964],{},[59,2972,2973],{},"Read-write-create"," as the mode, and click ",[59,2976,842],{}," to save the configuration.",[16,2979,2980,2984],{},[650,2981],{"alt":2982,"dataZoomable":230,"src":2983},"SQLite database configuration with read-write-create mode enabled","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fsqlite-config.png",[1529,2985,2982],{},[472,2987,2988],{"start":507},[56,2989,2990,2991,2994],{},"Set the SQL Query mode to ",[59,2992,2993],{},"Fixed Statement",". In the SQL Query field, enter:",[485,2996,3000],{"className":2997,"code":2998,"language":2999,"meta":230,"style":230},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","CREATE TABLE IF NOT EXISTS data_buffer (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    timestamp INTEGER NOT NULL,\n    sent INTEGER DEFAULT 0,\n    payload TEXT,\n    created_at INTEGER DEFAULT (strftime('%s','now') * 1000)\n);\n","sql",[349,3001,3002,3007,3012,3017,3022,3027,3032],{"__ignoreMap":230},[493,3003,3004],{"class":495,"line":496},[493,3005,3006],{},"CREATE TABLE IF NOT EXISTS data_buffer (\n",[493,3008,3009],{"class":495,"line":234},[493,3010,3011],{},"    id INTEGER PRIMARY KEY AUTOINCREMENT,\n",[493,3013,3014],{"class":495,"line":507},[493,3015,3016],{},"    timestamp INTEGER NOT NULL,\n",[493,3018,3019],{"class":495,"line":231},[493,3020,3021],{},"    sent INTEGER DEFAULT 0,\n",[493,3023,3024],{"class":495,"line":518},[493,3025,3026],{},"    payload TEXT,\n",[493,3028,3029],{"class":495,"line":524},[493,3030,3031],{},"    created_at INTEGER DEFAULT (strftime('%s','now') * 1000)\n",[493,3033,3034],{"class":495,"line":530},[493,3035,3036],{},");\n",[16,3038,3039,3040,3043],{},"The payload stores the serialized data as JSON. The ",[349,3041,3042],{},"sent"," flag indicates whether the record is still pending (0) or has been successfully delivered (1), this acts as a safety marker to prevent cleanup of unsent data.",[472,3045,3046,3056],{},[56,3047,3048,3049,3051,3052,3055],{},"Connect an ",[59,3050,2495],{}," node to ",[59,3053,3054],{},"Sqlite"," node",[56,3057,3058],{},"Deploy your flow and click the inject node button to create the table.",[16,3060,3061],{},"Your SQLite buffer is now ready to store data during network outages. The next step implements the logic to write incoming data to this buffer.",[1224,3063,3065],{"id":3064},"step-3-store-incoming-data-in-buffer","Step 3: Store Incoming Data in Buffer",[16,3067,3068],{},"With your SQLite buffer ready, implement the logic to write incoming PLC data to storage.",[472,3070,3071,3077],{},[56,3072,932,3073,3076],{},[59,3074,3075],{},"JSON"," node onto the canvas and connect it to your data input source.",[56,3078,3079,3080,3083,3084,3086,3087,3089],{},"Double-click the node to open its configuration. Set the Action to ",[349,3081,3082],{},"Always convert to JSON String"," and set the Property to ",[349,3085,2651],{},", then click ",[59,3088,848],{}," to save.",[328,3091,3092],{},[16,3093,3094,3097],{},[59,3095,3096],{},"Note",": JSON converts your data object into a text string for storage. If your data source already provides a JSON string (not an object), you must delete this node.",[16,3099,3100,3104],{},[650,3101],{"alt":3102,"dataZoomable":230,"src":3103},"JSON node configured to stringify payload data for storage","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fstringify-json.png",[1529,3105,3102],{},[472,3107,3108,3117],{"start":507},[56,3109,932,3110,3113,3114,3116],{},[59,3111,3112],{},"Change"," node onto the canvas and connect it to the ",[59,3115,3075],{}," node.",[56,3118,2511,3119,3121,3122],{},[59,3120,3112],{}," node to configure it. Add the following rules:",[53,3123,3124,3137,3148],{},[56,3125,3126,3129,3130,989,3133,3136],{},[59,3127,3128],{},"Rule 1",": Set ",[349,3131,3132],{},"msg.params",[349,3134,3135],{},"{}"," (JSONata expression)",[56,3138,3139,3129,3142,989,3145],{},[59,3140,3141],{},"Rule 2",[349,3143,3144],{},"msg.params.$ts",[349,3146,3147],{},"msg.timestamp",[56,3149,3150,3129,3153,989,3156],{},[59,3151,3152],{},"Rule 3",[349,3154,3155],{},"msg.params.$payload",[349,3157,2651],{},[16,3159,3160,3164],{},[650,3161],{"alt":3162,"dataZoomable":230,"src":3163},"Change node rules for preparing SQLite insert parameters","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fset-params-step-3.png",[1529,3165,3162],{},[472,3167,3168,3175],{"start":518},[56,3169,3170,3171,3113,3173,3116],{},"Drag another ",[59,3172,3054],{},[59,3174,3112],{},[56,3176,3177,3178,3180,3181,3184],{},"Double-click the node to configure it. Select your existing ",[59,3179,3054],{}," database, set the SQL Query mode to ",[349,3182,3183],{},"Prepared Statement",", and in the SQL Query field, enter:",[485,3186,3188],{"className":2997,"code":3187,"language":2999,"meta":230,"style":230},"INSERT INTO data_buffer (timestamp, payload, sent)\nVALUES ($ts, $payload, 0);\n",[349,3189,3190,3195],{"__ignoreMap":230},[493,3191,3192],{"class":495,"line":496},[493,3193,3194],{},"INSERT INTO data_buffer (timestamp, payload, sent)\n",[493,3196,3197],{"class":495,"line":234},[493,3198,3199],{},"VALUES ($ts, $payload, 0);\n",[472,3201,3202],{"start":530},[56,3203,635,3204,3206],{},[59,3205,848],{}," to save the configuration and deploy your flow.",[16,3208,3209,3210,3213],{},"Your buffer now accumulates all incoming data. Each data point is serialized to JSON, structured into parameters, and written to SQLite with ",[349,3211,3212],{},"sent=0"," (not yet forwarded). The prepared statement approach prevents SQL injection issues and handles special characters correctly.",[1224,3215,3217],{"id":3216},"step-4-monitor-network-connectivity","Step 4: Monitor Network Connectivity",[16,3219,3220],{},"Network connectivity monitoring determines when your system can forward buffered data. The ping node checks connectivity to your destination system, and when the network is available, it triggers the forwarding process.",[16,3222,3223],{},"Follow these steps to implement connectivity monitoring:",[472,3225,3226,3232],{},[56,3227,932,3228,3231],{},[59,3229,3230],{},"Ping"," node onto the canvas.",[56,3233,3234,3235,3238,3239,3242,3243,3089],{},"Double-click the node to configure it. Enter the IP address or hostname of your destination system in the Target field (e.g., ",[349,3236,3237],{},"broker.flowfuse.cloud","), select mode to \"Automatic\", set \"Ping every\" to ",[349,3240,3241],{},"30"," seconds (adjust based on your requirements), name it \"Network Health Check\", and click ",[59,3244,848],{},[16,3246,3247,3251],{},[650,3248],{"alt":3249,"dataZoomable":230,"src":3250},"Ping node configured to monitor network connectivity every 30 seconds","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fping.png",[1529,3252,3249],{},[472,3254,3255,3262],{"start":507},[56,3256,932,3257,3113,3260,3116],{},[59,3258,3259],{},"Switch",[59,3261,3230],{},[56,3263,2511,3264,3266,3267,3269,3270],{},[59,3265,3259],{}," node to configure it. Set the Property to ",[349,3268,2651],{},",",[53,3271,3272,3279],{},[56,3273,3274,3275,3278],{},"add Rule 1 as ",[349,3276,3277],{},"false"," (network is down),",[56,3280,3281,3282,3285],{},"add Rule 2 as ",[349,3283,3284],{},"otherwise"," (network is reachable).",[16,3287,3288,3292],{},[650,3289],{"alt":3290,"dataZoomable":230,"src":3291},"Switch node routing messages based on network connectivity status","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fif-connected-to-internet.png",[1529,3293,3290],{},[472,3295,3296],{"start":518},[56,3297,635,3298,3089],{},[59,3299,848],{},[16,3301,3302,3303,3305,3306,3308],{},"The switch node routes messages based on ping results. When ping fails, ",[349,3304,2651],{}," is ",[349,3307,3277],{},". Otherwise, the ping succeeded with a response time.",[472,3310,3311,3318],{"start":524},[56,3312,3313,3314,3317],{},"Drag two ",[59,3315,3316],{},"change"," nodes onto the canvas. Connect the first one to output 1 of the switch node (network down), and the second one to output 2 (network reachable).",[56,3319,3320,3321],{},"Double-click the first change node to configure it:",[53,3322,3323,3333,3336],{},[56,3324,3325,3129,3327,989,3330,3332],{},[59,3326,3128],{},[349,3328,3329],{},"flow.networkOnline",[349,3331,3277],{}," (boolean) ( make sure it is stored in the persistent storage )",[56,3334,3335],{},"Name it \"Set Network Offline\"",[56,3337,635,3338,3089],{},[59,3339,848],{},[16,3341,3342,3346],{},[650,3343],{"alt":3344,"dataZoomable":230,"src":3345},"Change node setting network offline flag in persistent storage","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fset-network-offline.png",[1529,3347,3344],{},[472,3349,3350],{"start":536},[56,3351,3352,3353],{},"Double-click the second change node to configure it:\n",[53,3354,3355,3365,3368],{},[56,3356,3357,3129,3359,989,3361,3364],{},[59,3358,3128],{},[349,3360,3329],{},[349,3362,3363],{},"true"," (boolean)",[56,3366,3367],{},"Name it \"Set Network Online\"",[56,3369,635,3370,3089],{},[59,3371,848],{},[16,3373,3374,3378],{},[650,3375],{"alt":3376,"dataZoomable":230,"src":3377},"Change node setting network online flag when connectivity is restored","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fset-network-online.png",[1529,3379,3376],{},[472,3381,3382],{"start":542},[56,3383,3170,3384,3386,3387],{},[59,3385,3316],{}," node onto the canvas and configure it:\n",[53,3388,3389],{},[56,3390,3391,3129,3393,989,3396,3398,3399,3403],{},[59,3392,3128],{},[349,3394,3395],{},"flow.flowError",[59,3397,3277],{}," (this resets the error state triggered in the ",[105,3400,3402],{"href":3401},"#handle-errors-and-disconnections","Handle Errors and Disconnections"," section).",[16,3405,3406,3410],{},[650,3407],{"alt":3408,"dataZoomable":230,"src":3409},"Change node resetting error state when network becomes available","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fflow-error.png",[1529,3411,3408],{},[472,3413,3414],{"start":548},[56,3415,932,3416,3419],{},[59,3417,3418],{},"Link Out"," node onto the canvas and connect it to the \"Set Network Online\" node. Name it \"Trigger Forward\".",[16,3421,3422],{},"Your connectivity monitoring is now complete. When the network is available, the system will trigger the forwarding logic to send buffered data.",[1224,3424,3426],{"id":3425},"step-5-build-the-forwarding-logic","Step 5: Build the Forwarding Logic",[16,3428,3429],{},"The forwarding logic retrieves unsent data from the buffer, prepares it for transmission, and sends it to the destination. This section shows how to build a forwarding system that processes buffered data in batches.",[3431,3432,3434],"h4",{"id":3433},"retrieve-and-prepare-unsent-records","Retrieve and Prepare Unsent Records",[472,3436,3437,3446],{},[56,3438,932,3439,3442,3443,3445],{},[59,3440,3441],{},"Link In"," node onto the canvas and name it \"Trigger Forward\". Link this to the ",[59,3444,3418],{}," node from Step 4.",[56,3447,878,3448,3113,3451,3453,3454,3457],{},[59,3449,3450],{},"SQLite",[59,3452,3441],{}," node. Name it \"Get Unsent Data\" and configure it by selecting your database, setting SQL Query mode to ",[59,3455,3456],{},"Fixed statement",", and entering the following SQL:",[485,3459,3461],{"className":2997,"code":3460,"language":2999,"meta":230,"style":230},"   SELECT * FROM data_buffer \n   WHERE sent = 0 \n   ORDER BY timestamp ASC \n   LIMIT 50;\n",[349,3462,3463,3468,3473,3478],{"__ignoreMap":230},[493,3464,3465],{"class":495,"line":496},[493,3466,3467],{},"   SELECT * FROM data_buffer \n",[493,3469,3470],{"class":495,"line":234},[493,3471,3472],{},"   WHERE sent = 0 \n",[493,3474,3475],{"class":495,"line":507},[493,3476,3477],{},"   ORDER BY timestamp ASC \n",[493,3479,3480],{"class":495,"line":231},[493,3481,3482],{},"   LIMIT 50;\n",[472,3484,3485,3489,3500],{"start":507},[56,3486,635,3487,3089],{},[59,3488,848],{},[56,3490,932,3491,3494,3495,3497,3498,285],{},[59,3492,3493],{},"Split"," node onto the canvas and connect it to the SQLite node. Configure it to split ",[59,3496,2651],{}," and click ",[59,3499,848],{},[56,3501,932,3502,3113,3504,3506,3507],{},[59,3503,3112],{},[59,3505,3493],{}," node. Name it \"Prepare Forward Message\" and add the following rules:",[53,3508,3509,3519],{},[56,3510,3511,3129,3513,989,3516],{},[59,3512,3128],{},[349,3514,3515],{},"msg.record_id",[349,3517,3518],{},"msg.payload.id",[56,3520,3521,3129,3523,989,3525],{},[59,3522,3141],{},[349,3524,2651],{},[349,3526,3527],{},"msg.payload.payload",[16,3529,3530,3534],{},[650,3531],{"alt":3532,"dataZoomable":230,"src":3533},"Change node extracting record ID and payload for forwarding","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fprepare-forward-msg.png",[1529,3535,3532],{},[472,3537,3538,3542],{"start":524},[56,3539,635,3540,3089],{},[59,3541,848],{},[56,3543,932,3544,3113,3546,3548,3549,3552,3553,3086,3555,285],{},[59,3545,3075],{},[59,3547,3112],{}," node. Configure it by setting Action to ",[59,3550,3551],{},"Always Convert to JSON Object"," and Property to ",[349,3554,2651],{},[59,3556,848],{},[16,3558,3559,3563],{},[650,3560],{"alt":3561,"dataZoomable":230,"src":3562},"JSON node configured to parse stored JSON string back to object","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fparse-json.png",[1529,3564,3561],{},[472,3566,3567,3571],{"start":536},[56,3568,635,3569,3089],{},[59,3570,848],{},[56,3572,932,3573,3113,3575,3577],{},[59,3574,3418],{},[59,3576,3075],{}," node. Name it \"Send to Destination\".",[16,3579,3580],{},"Your forwarding logic now retrieves unsent records, prepares them for transmission, and passes them to the next stage for sending.",[1224,3582,3584],{"id":3583},"step-6-send-data-and-handle-errors","Step 6: Send Data and Handle Errors",[16,3586,3587],{},"This step implements data transmission to your destination with comprehensive error handling and buffer management.",[3431,3589,3591],{"id":3590},"send-data-to-destination","Send Data to Destination",[472,3593,3594,3602],{},[56,3595,932,3596,3598,3599,3601],{},[59,3597,3441],{}," node onto the canvas and link it to the ",[59,3600,3418],{}," node from Step 5. Name it \"Send to Destination\".",[56,3603,932,3604,3113,3606,3608,3609,3611,3612,1279,3615,3089],{},[59,3605,3259],{},[59,3607,3441],{}," node. Name it \"Check Network Online\", set the Property to ",[349,3610,3329],{},", add a condition ",[349,3613,3614],{},"is true",[59,3616,848],{},[16,3618,3619,3623],{},[650,3620],{"alt":3621,"dataZoomable":230,"src":3622},"Switch node verifying network connectivity before sending data","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fis-network-online.png",[1529,3624,3621],{},[472,3626,3627],{"start":507},[56,3628,3170,3629,3631,3632,3611,3634,1279,3637,3089],{},[59,3630,3259],{}," node onto the canvas and connect it to the first switch node's output. Name it \"Check Flow Error\", set the Property to ",[349,3633,3395],{},[349,3635,3636],{},"is false",[59,3638,848],{},[16,3640,3641,3645],{},[650,3642],{"alt":3643,"dataZoomable":230,"src":3644},"Switch node checking for error-free state before transmission","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fif-no-error.png",[1529,3646,3643],{},[472,3648,3649],{"start":231},[56,3650,932,3651,3653,3654],{},[59,3652,3112],{}," node onto the canvas and connect it to the second switch node's output. Configure it to append the record ID into the payload for transmission confirmation:\n",[53,3655,3656],{},[56,3657,3658,3659,989,3661],{},"Rule 1: Set ",[349,3660,3515],{},[349,3662,3663],{},"msg.payload.record_id",[16,3665,3666,3670],{},[650,3667],{"alt":3668,"dataZoomable":230,"src":3669},"Change node preserving record ID for transmission confirmation","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fadd-record-id-to-payload.png",[1529,3671,3668],{},[472,3673,3674],{"start":518},[56,3675,932,3676,3113,3679,3681,3682,3685,3686,2977],{},[59,3677,3678],{},"Project Out",[59,3680,3112],{}," node. Double-click the node to open its configuration. Select \"Send to specified node\" as the mode, then enter select target \"broadcast message\" and enter topic (for example: ",[349,3683,3684],{},"acme_manufacturing\u002Fplant_01\u002Ffloor_2\u002Fcell_a\u002Fmachine_A12\u002Fmeasurements","). Click ",[59,3687,848],{},[328,3689,3690],{},[16,3691,3692,3694,3695,3698,3699,3702,3703,3706],{},[59,3693,830],{}," you can use any output node that suits your architecture instead of Project Out, such as ",[59,3696,3697],{},"MQTT Out"," for publishing to MQTT brokers, ",[59,3700,3701],{},"HTTP Request"," for sending data to REST APIs, ",[59,3704,3705],{},"Database"," nodes for writing directly to databases or other protocol-specific nodes depending on your destination requirements.",[472,3708,3709],{"start":524},[56,3710,3711],{},"Deploy the flow.",[3431,3713,3715],{"id":3714},"mark-records-as-sent-and-clear-buffer","Mark Records as Sent and Clear Buffer",[472,3717,3718],{},[56,3719,932,3720,3723],{},[59,3721,3722],{},"Project In"," node onto the canvas, double-click the node to configure it with source set to \"Listen for broadcast messages\", and configure it to listen on all instances and devices with the topic that should match the same topic you configured in the Project Out node earlier to subscribe to your data that was sent before.",[328,3725,3726],{},[16,3727,3728,3730],{},[59,3729,830],{}," The Project In node is used here to confirm successful transmission when using Project Out nodes. If you are using other output nodes such as MQTT Out, HTTP Request, or database nodes, replace the Project In node with the corresponding confirmation mechanism for your chosen protocol. For example, if your output node such as HTTP Request responds with a status code or success message, you can use that response directly for confirmation instead of the Project In node.",[472,3732,3733],{"start":234},[56,3734,932,3735,3113,3737,3739,3740],{},[59,3736,3112],{},[59,3738,3722],{}," node. Name it \"Prepare Record ID\" and configure the following rules:\n",[53,3741,3742,3753],{},[56,3743,3744,3129,3746,989,3748,3750,3751,2445],{},[59,3745,3128],{},[349,3747,3132],{},[349,3749,3135],{}," (JSONata expression: ",[349,3752,3135],{},[56,3754,3755,3129,3757,989,3760],{},[59,3756,3141],{},[349,3758,3759],{},"msg.params.$record_id",[349,3761,3515],{},[16,3763,3764,3768],{},[650,3765],{"alt":3766,"dataZoomable":230,"src":3767},"Change node preparing parameters for marking record as sent","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fset-params-step-5.png",[1529,3769,3766],{},[472,3771,3772,3776],{"start":507},[56,3773,635,3774,3089],{},[59,3775,848],{},[56,3777,878,3778,3113,3780,3782,3783,3785],{},[59,3779,3450],{},[59,3781,3112],{}," node. Name it \"Mark as Sent\", then double-click it to configure. Select your database, set SQL Query mode to ",[59,3784,3183],{},", and enter the following SQL:",[485,3787,3789],{"className":2997,"code":3788,"language":2999,"meta":230,"style":230},"   UPDATE data_buffer \n   SET sent = 1 \n   WHERE id = $record_id;\n",[349,3790,3791,3796,3801],{"__ignoreMap":230},[493,3792,3793],{"class":495,"line":496},[493,3794,3795],{},"   UPDATE data_buffer \n",[493,3797,3798],{"class":495,"line":234},[493,3799,3800],{},"   SET sent = 1 \n",[493,3802,3803],{"class":495,"line":507},[493,3804,3805],{},"   WHERE id = $record_id;\n",[472,3807,3808,3812],{"start":518},[56,3809,635,3810,3089],{},[59,3811,848],{},[56,3813,3170,3814,3816,3817,3785],{},[59,3815,3450],{}," node onto the canvas and connect it to the previous SQLite node. Name it \"Delete Record\", then double-click it to configure. Select database, set SQL Query mode to ",[59,3818,3183],{},[485,3820,3822],{"className":2997,"code":3821,"language":2999,"meta":230,"style":230},"   DELETE FROM data_buffer\n   WHERE id = $record_id\n   AND sent = 1;\n",[349,3823,3824,3829,3834],{"__ignoreMap":230},[493,3825,3826],{"class":495,"line":496},[493,3827,3828],{},"   DELETE FROM data_buffer\n",[493,3830,3831],{"class":495,"line":234},[493,3832,3833],{},"   WHERE id = $record_id\n",[493,3835,3836],{"class":495,"line":507},[493,3837,3838],{},"   AND sent = 1;\n",[472,3840,3841],{"start":530},[56,3842,635,3843,3845],{},[59,3844,848],{}," to save and deploy the flow.",[3431,3847,3402],{"id":3848},"handle-errors-and-disconnections",[472,3850,3851,3857,3863],{},[56,3852,932,3853,3856],{},[59,3854,3855],{},"Catch"," node onto the canvas. Configure it to catch errors from all nodes.",[56,3858,932,3859,3113,3861,3116],{},[59,3860,3112],{},[59,3862,3855],{},[56,3864,3865,3866],{},"Name it \"Set Flow Error\" and configure it:",[53,3867,3868],{},[56,3869,3870,3129,3872,989,3874,3364],{},[59,3871,3128],{},[349,3873,3395],{},[349,3875,3363],{},[16,3877,3878,3882],{},[650,3879],{"alt":3880,"dataZoomable":230,"src":3881},"Change node setting error flag when transmission fails","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fset-flow-error-flag.png",[1529,3883,3880],{},[472,3885,3886,3890,3900,3905,3920,3926,3939],{"start":231},[56,3887,635,3888,3089],{},[59,3889,848],{},[56,3891,932,3892,3895,3896,3899],{},[59,3893,3894],{},"Status"," node onto the canvas and configure it to monitor the ",[59,3897,3898],{},"Project"," node's status.",[56,3901,932,3902,3904],{},[59,3903,3259],{}," node onto the canvas and connect it to the status node.",[56,3906,3907,3908,3611,3911,3914,3915,1279,3918,3089],{},"Name it \"Check Disconnected\", set the Property to ",[349,3909,3910],{},"msg.status.text",[349,3912,3913],{},"=="," with value ",[349,3916,3917],{},"disconnected",[59,3919,848],{},[56,3921,932,3922,3113,3924,3116],{},[59,3923,3112],{},[59,3925,3259],{},[56,3927,3928,3929],{},"Name it \"Set Network Failure Flag\" and configure it:",[53,3930,3931],{},[56,3932,3933,3129,3935,989,3937,3364],{},[59,3934,3128],{},[349,3936,3329],{},[349,3938,3277],{},[56,3940,635,3941,3943],{},[59,3942,848],{}," to save and deploy your flow.",[26,3945,1456],{"id":1455},[16,3947,3948],{},"You now have a working store-and-forward system that protects your data during network failures.",[16,3950,3951],{},"When the network is up, data flows through the buffer and transmits immediately. When the network goes down, data accumulates in SQLite. When connectivity returns, the buffered data forwards automatically while new data continues collecting. No data is lost, regardless of how long the outage lasts.",[16,3953,3954],{},"This pattern solves a common problem in industrial environments: maintaining complete time-series data when network infrastructure fails. Your production systems can now operate independently of network reliability.",[16,3956,3957],{},"The system you've built is production-ready as-is, but you can extend it based on your requirements, add monitoring for buffer capacity, implement data validation rules, or configure forwarding to multiple destinations. The core mechanism remains the same.",[16,3959,3960,3961,285],{},"If you want to get the flow template that you can use directly and modify according to your needs, check out our ",[105,3962,3964],{"href":3963},"\u002Fblueprints\u002Fgetting-started\u002Fstore-and-forward\u002F","latest blueprint",[16,3966,3967,3968,285],{},"Store-and-forward is just one part of a complete PLC integration. For the full picture, connecting Siemens, Allen-Bradley, Omron, and other PLCs to MQTT, cloud, and enterprise systems, see the ",[105,3969,1475],{"href":1474},[1477,3971,1479],{},{"title":230,"searchDepth":231,"depth":231,"links":3973},[3974,3975,3990],{"id":2737,"depth":234,"text":2738},{"id":2895,"depth":234,"text":2896,"children":3976},[3977,3978,3979,3980,3981,3982,3985],{"id":288,"depth":507,"text":289},{"id":2930,"depth":507,"text":2931},{"id":2949,"depth":507,"text":2950},{"id":3064,"depth":507,"text":3065},{"id":3216,"depth":507,"text":3217},{"id":3425,"depth":507,"text":3426,"children":3983},[3984],{"id":3433,"depth":231,"text":3434},{"id":3583,"depth":507,"text":3584,"children":3986},[3987,3988,3989],{"id":3590,"depth":231,"text":3591},{"id":3714,"depth":231,"text":3715},{"id":3848,"depth":231,"text":3402},{"id":1455,"depth":234,"text":1456},"2025-11-21","Learn how to implement store-and-forward buffering for data collection. This guide shows you how to build an edge system with FlowFuse that maintains complete data continuity during network outages, preventing production data loss and compliance gaps.","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fstore-and-forward.png",{"keywords":3995,"excerpt":3996},"store-and-forward, edge computing, PLC data buffering, network resilience, industrial IoT, data continuity, FlowFuse, SQLite buffering, SCADA data collection, network outage recovery",{"type":13,"value":3997},[3998],[16,3999,2719],{},"\u002Fblog\u002F2025\u002F11\u002Fstore-and-forward-edge-data-buffering",{"title":2713,"description":3992},{"loc":4000},"blog\u002F2025\u002F11\u002Fstore-and-forward-edge-data-buffering","Keep collecting data when your network goes down",[1518,263],"Network outages leave PLCs running while their data has nowhere to go, creating gaps in production records, audit trails, and compliance documentation. Store-and-forward solves this by writing every data point to a local SQLite buffer first, then forwarding it when connectivity is available. This guide builds the pattern in FlowFuse and Node-RED across six steps, covering data collection, SQLite buffering, connectivity monitoring with a ping node, batched forwarding of unsent records, and error handling, so no data is lost regardless of how long the outage lasts.","s2Qvb5N3ua8ltFODDooTaOMcSiDjw7JYNybyruPcjDw",{"id":4009,"title":4010,"authors":4011,"body":4012,"cta":3,"date":4969,"description":4970,"extension":248,"image":4971,"lastUpdated":1506,"meta":4972,"navigation":255,"path":4980,"seo":4981,"sitemap":4982,"stem":4983,"subtitle":4984,"tags":4985,"tldr":3,"video":3,"__hash__":4986},"blog\u002Fblog\u002F2025\u002F11\u002Fbuilding-hmi-for-equipment-control.md","Building a Web HMI for Factory Equipment Control",[11],{"type":13,"value":4013,"toc":4955},[4014,4017,4020,4023,4026,4029,4031,4034,4054,4058,4061,4064,4067,4070,4074,4077,4086,4089,4092,4096,4099,4105,4109,4112,4115,4180,4185,4207,4212,4215,4234,4248,4255,4269,4274,4292,4295,4299,4302,4306,4326,4330,4335,4379,4388,4405,4414,4418,4421,4426,4444,4453,4481,4490,4499,4504,4539,4548,4553,4575,4694,4703,4710,4719,4723,4728,4731,4749,4758,4777,4786,4793,4798,4801,4804,4809,4817,4822,4825,4873,4876,4881,4889,4921,4928,4932,4935,4938,4941,4947,4952],[16,4015,4016],{},"Most factory HMIs are still stuck in one place. Dedicated panels mounted next to equipment, or SCADA workstations in the control room. Need to check something? You're walking over there.",[16,4018,4019],{},"Web-based HMIs change that. Build your interface once in FlowFuse, and it runs anywhere, desktop, tablet, phone. Your operators can monitor and control equipment from wherever they need to be.",[16,4021,4022],{},"This tutorial walks you through building a simple motor control interface: two buttons and a status display. You will learn how to connect to PLCs, build HMI dashboards, and enable remote access. From there, you can scale up to production lines with multiple sensors and actuators, live charts, gauges, sliders, and interactive controls.",[16,4024,4025],{},"Here's what you'll build:",[950,4027],{"videoid":4028,"params":2732,"style":2733,"title":2734},"NQZ_u25sy1Q",[26,4030,289],{"id":288},[16,4032,4033],{},"Before beginning, ensure you have:",[53,4035,4036,4042,4048],{},[56,4037,4038,4041],{},[59,4039,4040],{},"Edge device"," - A computer, Raspberry Pi, or industrial PC that connects to your PLC and runs FlowFuse",[56,4043,4044,4047],{},[59,4045,4046],{},"PLC on the same network"," - Your PLC must be networked with your edge device",[56,4049,4050,4053],{},[59,4051,4052],{},"Equipment to control"," (optional but recommended) - Having a motor or other equipment connected to your PLC helps you follow along and see real results as you build the HMI",[26,4055,4057],{"id":4056},"understanding-the-setup","Understanding the Setup",[16,4059,4060],{},"Your PLC already controls your equipment. It reads sensors, executes logic, and switches outputs. That doesn't change.",[16,4062,4063],{},"FlowFuse sits between operators and the PLC. It runs on an edge device connected to the same network as your PLC. FlowFuse communicates with the PLC using Modbus, OPC UA, EtherNet\u002FIP, S7, or whatever protocol your PLC speaks.",[16,4065,4066],{},"Inside FlowFuse, nodes handle the PLC communication and data transformation while dashboard nodes let you build the HMI. These nodes create buttons, gauges, charts, and status displays. FlowFuse serves this interface as a webpage that any browser can access.",[16,4068,4069],{},"When an operator clicks a button, FlowFuse writes the command to the PLC. When the PLC updates its output, FlowFuse reads it and pushes the new value to the dashboard. The browser updates automatically.",[26,4071,4073],{"id":4072},"hmi-design-principles-worth-knowing","HMI Design Principles Worth Knowing",[16,4075,4076],{},"Before diving into the build, it's helpful to understand what makes industrial HMIs effective. Our tutorial keeps things simple, but these principles are worth knowing as you get more comfortable with FlowFuse and expand your system.",[16,4078,4079,4080,4085],{},"Good HMIs let operators quickly assess what's happening at a glance. Status should be immediately obvious: what is running, what is stopped, what needs attention. Color coding helps with this: green for running, red for stopped, yellow for warnings. Following standards like ",[105,4081,4084],{"href":4082,"rel":4083},"https:\u002F\u002Fwww.isa.org\u002Fstandards-and-publications\u002Fisa-standards\u002Fisa-101-standards",[1240],"ISA-101"," ensures your color choices are consistent with what operators expect across different systems. We'll use this approach in our motor control example.",[16,4087,4088],{},"Your PLC handles real-time control, your HMI just reflects what's happening. Polling intervals between 500-1000ms work well for most applications. Faster polling doesn't improve control, it just increases network traffic. Status indicators should be large and clear, with critical information immediately visible and text readable from a reasonable distance.",[16,4090,4091],{},"If operators will use tablets, design for touch targets (minimum 44x44 pixels) and avoid interactions that depend on hovering. Test on actual devices your team will use. Most importantly, always show operators when the HMI is disconnected from the PLC. This is critical for safety, operators need to know immediately if their commands aren't reaching the equipment. Display connection status prominently, and consider disabling controls when disconnected.",[26,4093,4095],{"id":4094},"step-1-set-up-flowfuse","Step 1: Set Up FlowFuse",[16,4097,4098],{},"You need the FlowFuse agent running on an edge device that can reach your PLC over the network.",[16,4100,4101,4102],{},"Start by creating a [FlowFuse account]({% include \"sign-up-url.njk\" %}). Once logged in, install and register the FlowFuse agent on your edge device by following this guide: ",[105,4103,4104],{"href":303},"Installing Node-RED on Your Edge Device",[26,4106,4108],{"id":4107},"step-2-connect-to-your-plc","Step 2: Connect to Your PLC",[16,4110,4111],{},"Your HMI needs to talk to your PLC to read equipment status and send control commands. FlowFuse handles this through Node-RED's protocol nodes, which support every major industrial controller. No proprietary gateways, no per-tag licensing, no vendor lock-in, just direct communication with your PLC.",[16,4113,4114],{},"Choose the node that matches your PLC:",[53,4116,4117,4126,4134,4141,4150,4160,4170],{},[56,4118,4119,4125],{},[59,4120,4121],{},[105,4122,4124],{"href":4123},"\u002Fnode-red\u002Fprotocol\u002Fmodbus\u002F","node-red-contrib-modbus"," – Modbus RTU\u002FTCP PLCs and devices",[56,4127,4128,4133],{},[59,4129,4130],{},[105,4131,2049],{"href":4132},"\u002Fblog\u002F2025\u002F01\u002Fintegrating-siemens-s7-plcs-with-node-red-guide\u002F"," – Siemens S7-300\u002F400\u002F1200\u002F1500",[56,4135,4136,4140],{},[59,4137,4138],{},[105,4139,2387],{"href":2660}," – OPC UA servers (universal industrial standard)",[56,4142,4143,4149],{},[59,4144,4145],{},[105,4146,4148],{"href":4147},"\u002Fblog\u002F2025\u002F10\u002Fusing-ethernet-ip-with-flowfuse\u002F","node-red-contrib-cip-ethernet-ip"," – Allen-Bradley\u002FRockwell PLCs",[56,4151,4152,4159],{},[59,4153,4154],{},[105,4155,4158],{"href":4156,"rel":4157},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-mcprotocol",[1240],"node-red-contrib-mcprotocol"," – Mitsubishi PLCs",[56,4161,4162,4169],{},[59,4163,4164],{},[105,4165,4168],{"href":4166,"rel":4167},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-omron-fins",[1240],"node-red-contrib-omron-fins"," – Omron PLCs",[56,4171,4172,4179],{},[59,4173,4174],{},[105,4175,4178],{"href":4176,"rel":4177},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-bacnet",[1240],"node-red-contrib-bacnet"," – BACnet building automation devices",[16,4181,4182],{},[59,4183,4184],{},"Installing Protocol Nodes:",[472,4186,4187,4192,4197,4203],{},[56,4188,4189,4190,285],{},"Click the hamburger menu (top right) → ",[59,4191,2377],{},[56,4193,622,4194,4196],{},[59,4195,625],{}," tab.",[56,4198,4199,4200,4202],{},"Search for your protocol node (e.g., ",[349,4201,2049],{}," for Siemens).",[56,4204,635,4205,285],{},[59,4206,625],{},[16,4208,4209],{},[59,4210,4211],{},"Configuring Your Connection",[16,4213,4214],{},"After installation, drag the protocol node onto your canvas. You’ll need two types of nodes: one for reading equipment status and one for sending commands.",[16,4216,4217,4218,4221,4222,4225,4226,4229,4230,4233],{},"Start with an input node for reading status (motor running, faults, sensor values). Use ",[59,4219,4220],{},"S7 In"," for Siemens, ",[59,4223,4224],{},"Modbus Read"," for Modbus devices, or ",[59,4227,4228],{},"OPC UA Client"," for OPC UA servers, etc. Open the node configuration and click the pencil icon next to the ",[59,4231,4232],{},"Server\u002FConnection"," dropdown to create a new connection configuration. Here, enter the connection details for your PLC or server, such as IP address, port, credentials, and polling interval. The exact parameters vary by protocol; if you need help understanding what to configure, refer to the documentation links in the protocol node list above. Each link includes detailed setup guidance.",[16,4235,4236,4237,4240,4241,1144,4244,4247],{},"After saving the connection configuration, specify the ",[59,4238,4239],{},"variable addresses that provide the status information"," you want to read (tags\u002Fregisters such as motor state, faults, and sensor values). If available, enable efficiency features like ",[59,4242,4243],{},"“emit only on change”",[59,4245,4246],{},"“subscribe mode”"," to minimize unnecessary updates.",[16,4249,4250,4251,4254],{},"For sending commands (start motor, stop motor, setpoints), drag the corresponding output node onto your canvas. When configuring it, select the ",[59,4252,4253],{},"same Server\u002FConnection"," from the dropdown instead of creating a new one. This shared connection approach means the IP address, port, and credentials only need to be configured once and can be reused across all your PLC\u002Fserver nodes. You then only need to specify the variable addresses that control your equipment, and connect those nodes to your dashboard buttons or automation logic.",[16,4256,4257,4260,4261,4264,4265,4268],{},[59,4258,4259],{},"Important Note:"," Some PLCs require configuration in their engineering software before allowing external access. For example, Siemens S7 requires ",[59,4262,4263],{},"PUT\u002FGET communication"," enabled in TIA Portal, and Allen-Bradley controllers may need ",[59,4266,4267],{},"explicit messaging"," enabled in Studio 5000. Refer to your PLC’s documentation for any communication prerequisites.",[16,4270,4271],{},[59,4272,4273],{},"Test Your Connection:",[472,4275,4276,4282,4286,4289],{},[56,4277,4278,4279,4281],{},"Add a ",[59,4280,2505],{}," node and connect it to your input node.",[56,4283,635,4284,285],{},[59,4285,853],{},[56,4287,4288],{},"Check for a green \"connected\" or \"online\" status indicator on your protocol node.",[56,4290,4291],{},"Open the debug panel to verify data is flowing from your PLC.",[16,4293,4294],{},"Once you see live values in the debug panel, your PLC connection is working and you're ready to build the operator interface.",[26,4296,4298],{"id":4297},"step-3-build-your-hmi-dashboard","Step 3: Build Your HMI Dashboard",[16,4300,4301],{},"With your PLC connected, let's create the operator interface using FlowFuse Dashboard, a set of UI nodes that build web-based interfaces without writing HTML or JavaScript.",[1224,4303,4305],{"id":4304},"install-dashboard-20","Install Dashboard 2.0",[472,4307,4308,4313,4317,4322],{},[56,4309,4310,4311,285],{},"Click the hamburger menu and select ",[59,4312,2377],{},[56,4314,622,4315,4196],{},[59,4316,625],{},[56,4318,629,4319,285],{},[349,4320,4321],{},"@flowfuse\u002Fnode-red-dashboard",[56,4323,635,4324,285],{},[59,4325,625],{},[1224,4327,4329],{"id":4328},"create-your-motor-control-interface","Create Your Motor Control Interface",[16,4331,4332],{},[59,4333,4334],{},"Add Control Buttons:",[472,4336,4337,4343,4346,4349,4352],{},[56,4338,932,4339,4342],{},[59,4340,4341],{},"ui-button"," widget onto your canvas.",[56,4344,4345],{},"Double-click to open its configuration.",[56,4347,4348],{},"Click the pencil icon next to \"Group\" to create a new group name, example, \"Motor Controls\" or another name that fits your equipment.",[56,4350,4351],{},"Click the pencil icon next to \"Page\" to create a new page like \"Line 1\", for example, \"Line 1\" or the area of your process this interface belongs to.",[56,4353,4354,4355],{},"Configure the button:\n",[53,4356,4357,4363,4371],{},[56,4358,4359,4362],{},[59,4360,4361],{},"Label",": \"Start\"",[56,4364,4365,4368,4369,3364],{},[59,4366,4367],{},"Payload",": ",[349,4370,3363],{},[56,4372,4373,4368,4376],{},[59,4374,4375],{},"Background",[349,4377,4378],{},"#28A745",[16,4380,4381,4385],{},[650,4382],{"alt":4383,"dataZoomable":230,"src":4384},"Button node configuration showing Start label, true payload, and green background color","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fstart-button.png",[1529,4386,4387],{},"Start button node configuration",[472,4389,4390,4393,4396],{"start":524},[56,4391,4392],{},"Click Done.",[56,4394,4395],{},"Connect this node to your PLC write node.",[56,4397,4398,4399,811,4401,4404],{},"Repeat to add a \"Stop\" button with payload ",[349,4400,3277],{},[349,4402,4403],{},"#DC3545"," background.",[16,4406,4407,4411],{},[650,4408],{"alt":4409,"dataZoomable":230,"src":4410},"Button node configuration showing Stop label, false payload, and red background color","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fstop-button.png",[1529,4412,4413],{},"Stop button node configuration",[1224,4415,4417],{"id":4416},"add-status-display","Add Status Display",[16,4419,4420],{},"The PLC continuously reports whether the motor is running or stopped as a boolean value. We'll convert these values into readable text with color-coded styling.",[16,4422,4423],{},[59,4424,4425],{},"Convert Boolean Values to Readable Status:",[472,4427,4428,4434],{},[56,4429,932,4430,4433],{},[59,4431,4432],{},"switch"," node onto the canvas and connect it to your PLC read node.",[56,4435,4436,4437,811,4439,4441,4442,285],{},"Add two conditions: ",[349,4438,3614],{},[349,4440,3636],{}," to check ",[349,4443,2651],{},[16,4445,4446,4450],{},[650,4447],{"alt":4448,"dataZoomable":230,"src":4449},"Switch node configuration showing conditions for true and false values","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fswitch-node.png",[1529,4451,4452],{},"Switch node configuration for motor status",[472,4454,4455],{"start":507},[56,4456,3313,4457,4459,4460],{},[59,4458,3316],{}," nodes onto the canvas:\n",[53,4461,4462,4472],{},[56,4463,4464,4465,4467,4468,4471],{},"Connect the first to the \"true\" output: set ",[349,4466,2651],{}," to \"RUNNING\" and ",[349,4469,4470],{},"msg.class"," to \"running\"",[56,4473,4474,4475,4477,4478,4480],{},"Connect the second to the \"false\" output: set ",[349,4476,2651],{}," to \"STOPPED\" and ",[349,4479,4470],{}," to \"stopped\"",[16,4482,4483,4487],{},[650,4484],{"alt":4485,"dataZoomable":230,"src":4486},"Change node configuration setting payload to RUNNING and class to running","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fchange-node-running.png",[1529,4488,4489],{},"Change node configuration for running status",[16,4491,4492,4496],{},[650,4493],{"alt":4494,"dataZoomable":230,"src":4495},"Change node configuration setting payload to STOPPED and class to stopped","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fchange-node-stopped.png",[1529,4497,4498],{},"Change node configuration for stopped status",[16,4500,4501],{},[59,4502,4503],{},"Create the Status Display:",[472,4505,4506,4511,4534,4536],{},[56,4507,932,4508,4342],{},[59,4509,4510],{},"ui-text",[56,4512,4513,4514],{},"Double-click to configure:\n",[53,4515,4516,4522,4527],{},[56,4517,4518,4521],{},[59,4519,4520],{},"Group",": Select \"Motor Controls\" (or create a \"Status\" group).",[56,4523,4524,4526],{},[59,4525,4361],{},": Leave empty or enter \"Motor Status:\"",[56,4528,4529,4368,4532,285],{},[59,4530,4531],{},"Value Format",[349,4533,2651],{},[56,4535,4392],{},[56,4537,4538],{},"Connect both change nodes to the ui-text widget.",[16,4540,4541,4545],{},[650,4542],{"alt":4543,"dataZoomable":230,"src":4544},"UI text widget configuration for displaying motor status","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fmotor-status-text-widget.png",[1529,4546,4547],{},"Motor status text widget configuration",[16,4549,4550],{},[59,4551,4552],{},"Add Status Styling:",[472,4554,4555,4561],{},[56,4556,932,4557,4560],{},[59,4558,4559],{},"ui-template"," widget onto the canvas.",[56,4562,4563,4564],{},"Configure:\n",[53,4565,4566,4572],{},[56,4567,4568,4571],{},[59,4569,4570],{},"Type",": Select \"CSS (All Pages)\" or \"CSS (Single Page)\".",[56,4573,4574],{},"Add this CSS:",[485,4576,4580],{"className":4577,"code":4578,"language":4579,"meta":230,"style":230},"language-css shiki shiki-themes material-theme-lighter material-theme material-theme-palenight",".running {\n    color: lightgreen !important;\n    font-size: 60px !important;\n    font-weight: bold;\n}\n.stopped {\n    color: red !important;\n    font-size: 60px !important;\n    font-weight: bold;\n}\n","css",[349,4581,4582,4594,4614,4629,4641,4646,4655,4668,4680,4690],{"__ignoreMap":230},[493,4583,4584,4587,4591],{"class":495,"line":496},[493,4585,285],{"class":4586},"sMK4o",[493,4588,4590],{"class":4589},"sBMFI","running",[493,4592,4593],{"class":4586}," {\n",[493,4595,4596,4600,4603,4607,4611],{"class":495,"line":234},[493,4597,4599],{"class":4598},"sqsOY","    color",[493,4601,4602],{"class":4586},":",[493,4604,4606],{"class":4605},"sTEyZ"," lightgreen ",[493,4608,4610],{"class":4609},"sbssI","!important",[493,4612,4613],{"class":4586},";\n",[493,4615,4616,4619,4621,4624,4627],{"class":495,"line":507},[493,4617,4618],{"class":4598},"    font-size",[493,4620,4602],{"class":4586},[493,4622,4623],{"class":4609}," 60px",[493,4625,4626],{"class":4609}," !important",[493,4628,4613],{"class":4586},[493,4630,4631,4634,4636,4639],{"class":495,"line":231},[493,4632,4633],{"class":4598},"    font-weight",[493,4635,4602],{"class":4586},[493,4637,4638],{"class":4605}," bold",[493,4640,4613],{"class":4586},[493,4642,4643],{"class":495,"line":518},[493,4644,4645],{"class":4586},"}\n",[493,4647,4648,4650,4653],{"class":495,"line":524},[493,4649,285],{"class":4586},[493,4651,4652],{"class":4589},"stopped",[493,4654,4593],{"class":4586},[493,4656,4657,4659,4661,4664,4666],{"class":495,"line":530},[493,4658,4599],{"class":4598},[493,4660,4602],{"class":4586},[493,4662,4663],{"class":4605}," red ",[493,4665,4610],{"class":4609},[493,4667,4613],{"class":4586},[493,4669,4670,4672,4674,4676,4678],{"class":495,"line":536},[493,4671,4618],{"class":4598},[493,4673,4602],{"class":4586},[493,4675,4623],{"class":4609},[493,4677,4626],{"class":4609},[493,4679,4613],{"class":4586},[493,4681,4682,4684,4686,4688],{"class":495,"line":542},[493,4683,4633],{"class":4598},[493,4685,4602],{"class":4586},[493,4687,4638],{"class":4605},[493,4689,4613],{"class":4586},[493,4691,4692],{"class":495,"line":548},[493,4693,4645],{"class":4586},[16,4695,4696,4700],{},[650,4697],{"alt":4698,"dataZoomable":230,"src":4699},"UI template node with CSS styling for running and stopped status classes","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fcss.png",[1529,4701,4702],{},"CSS template for status display styling",[472,4704,4705],{"start":507},[56,4706,635,4707,4709],{},[59,4708,848],{}," and deploy the flow",[16,4711,4712,4713,4718],{},"You've just built a basic motor control interface. FlowFuse Dashboard includes gauges, charts, sliders, and other widgets that work the same way, drag, configure, connect. See the ",[105,4714,4717],{"href":4715,"rel":4716},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets.html",[1240],"widget reference"," for the full list.",[1224,4720,4722],{"id":4721},"accessing-your-dashboard","Accessing Your Dashboard",[16,4724,4725],{},[59,4726,4727],{},"Local Network Access:",[16,4729,4730],{},"The dashboard in a remote instance isn't accessible by default. To enable it:",[472,4732,4733,4743],{},[56,4734,4735,4736,4739,4740,285],{},"Go to ",[59,4737,4738],{},"Instance Settings"," → ",[59,4741,4742],{},"Security",[56,4744,1376,4745,4748],{},[59,4746,4747],{},"\"Allow Offline Access\""," and set a username and password.",[16,4750,4751,4755],{},[650,4752],{"alt":4753,"dataZoomable":230,"src":4754},"Instance security settings showing Allow Offline Access checkbox and authentication fields","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fenable-offline-access.png",[1529,4756,4757],{},"Enabling offline access in instance security settings",[472,4759,4760,4770],{"start":507},[56,4761,635,4762,4765,4766,4769],{},[59,4763,4764],{},"save settings",", then restart the instance using the top-right ",[59,4767,4768],{},"action"," button dropdown",[56,4771,4772,4773,4776],{},"Navigate to ",[349,4774,4775],{},"http:\u002F\u002F[device-IP]:1880\u002Fdashboard"," in your browser.",[16,4778,4779,4783],{},[650,4780],{"alt":4781,"dataZoomable":230,"src":4782},"Web browser displaying the completed motor control HMI with start\u002Fstop buttons and status display","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fflowfuse-dashboard-hmi.png",[1529,4784,4785],{},"Completed HMI dashboard running in browser",[328,4787,4788],{},[16,4789,4790,4792],{},[59,4791,830],{}," While offline access is convenient for testing purposes, it should be avoided in production environments. Running the dashboard locally may bypass secure authentication, potentially exposing sensitive controls and data. For production deployments, we recommend using a FlowFuse-hosted instance, which provides proper security. Setup instructions are available below.",[16,4794,4795],{},[59,4796,4797],{},"Remote Access:",[16,4799,4800],{},"While a local dashboard works for on-site monitoring, it’s not ideal for production. A FlowFuse hosted instance lets you securely monitor and control your equipment from anywhere. Your edge device remains behind your factory network, while the hosted instance subscribes to PLC data via MQTT and displays it on the dashboard.",[16,4802,4803],{},"The architecture is straightforward: your edge device publishes PLC data to MQTT topics, and a hosted FlowFuse instance subscribes to those topics to display the data. When an operator clicks a control button in the hosted dashboard, it publishes a command to MQTT, which your edge device receives and writes to the PLC.",[16,4805,4806],{},[59,4807,4808],{},"Enable MQTT in Your Team:",[16,4810,4811,4812,4816],{},"Before you can use MQTT, you need to ",[105,4813,4815],{"href":4814},"\u002Fblog\u002F2025\u002F10\u002Fplc-to-mqtt-using-flowfuse\u002F","enable the FlowFuse MQTT broker"," for your team, a one-time setup in your FlowFuse team settings that also covers PLC to MQTT integration in depth.",[16,4818,4819],{},[59,4820,4821],{},"Configure Your Edge Device:",[16,4823,4824],{},"On your remote instance (the one connected to your PLC), you'll publish status data and subscribe to commands:",[472,4826,4827,4832,4838,4848,4854,4857,4867,4870],{},[56,4828,878,4829,3231],{},[59,4830,4831],{},"ff-mqtt-out",[56,4833,4834,4835,285],{},"Double-click to open configuration and click ",[59,4836,4837],{},"\"Configure access control\"",[56,4839,4840,4841,811,4844,4847],{},"FlowFuse automatically creates an MQTT client for your instance, enable both ",[59,4842,4843],{},"Publish",[59,4845,4846],{},"Subscribe"," permissions.",[56,4849,4850,4851],{},"Set the topic to something descriptive like: ",[349,4852,4853],{},"factory\u002Fline1\u002Fmotor\u002Fstatus",[56,4855,4856],{},"Connect this node to your PLC read node (the one that gets motor status).",[56,4858,4859,4860,4863,4864],{},"Add an ",[59,4861,4862],{},"ff-mqtt-in"," node and set its topic to: ",[349,4865,4866],{},"factory\u002Fline1\u002Fmotor\u002Fcommand",[56,4868,4869],{},"Connect this node to your PLC write node (the one that controls the motor).",[56,4871,4872],{},"Deploy your flow.",[16,4874,4875],{},"Your edge device now shares motor status via MQTT and listens for control commands.",[16,4877,4878],{},[59,4879,4880],{},"Build Your Remote Dashboard:",[16,4882,4883,4884,4888],{},"Create a new ",[105,4885,4887],{"href":4886},"\u002Fdocs\u002Fuser\u002Fintroduction\u002F#creating-a-node-red-instance","hosted instance"," in FlowFuse. This instance runs in the cloud and will host your operator dashboard:",[472,4890,4891,4897,4900,4908,4915,4918],{},[56,4892,4893,4894,4896],{},"Install ",[349,4895,4321],{}," using Manage Palette.",[56,4898,4899],{},"Build your control interface following the same steps as before, add ui-button widgets for start\u002Fstop and ui-text widgets for status display.",[56,4901,4859,4902,4904,4905,4907],{},[59,4903,4862],{}," node with topic ",[349,4906,4853],{}," and connect it to your status display widgets.",[56,4909,4859,4910,4904,4912,4914],{},[59,4911,4831],{},[349,4913,4866],{}," and connect it to your control buttons.",[56,4916,4917],{},"Configure access control for this hosted instance's MQTT client (enable Publish and Subscribe).",[56,4919,4920],{},"Deploy.",[16,4922,4923,4924,4927],{},"Your dashboard is now accessible at ",[349,4925,4926],{},"https:\u002F\u002F[your-instance].flowfuse.cloud\u002Fdashboard"," from any device with internet access. Commands flow from the hosted dashboard through MQTT to your edge device, then to your PLC. Status updates travel the reverse path.",[26,4929,4931],{"id":4930},"next-steps","Next Steps",[16,4933,4934],{},"You now have a working HMI that controls real equipment from any browser. The same approach scales to more equipment, motors, conveyors, pumps, valves, just repeat the connection and dashboard steps.",[16,4936,4937],{},"As your system grows, organize controls across multiple dashboard pages for different production lines or work cells. Add chart widgets to visualize production rates, cycle times, and sensor trends. Configure notification nodes to alert your team via email or Telegram when faults occur.",[16,4939,4940],{},"And if you need to deploy the solution across many production lines, FlowFuse's DevOps features help you manage the scale. Build your HMI once, then deploy it across multiple edge devices and push updates centrally without visiting each location.",[16,4942,4943,4944,285],{},"For a full view of the PLC brands and protocols FlowFuse supports, Siemens, Allen-Bradley, Omron, OPC UA, Modbus, and more, see ",[105,4945,4946],{"href":1474},"how FlowFuse connects any PLC to the modern industrial stack",[16,4948,4949,4951],{},[105,4950,1935],{"href":1934}," to see how FlowFuse can help your organization connect, collect, transform, and visualize industrial data with our low-code and AI-powered editor, without the hassle of infrastructure management, deployment complexities, or security concerns at scale.",[1477,4953,4954],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sqsOY, html code.shiki .sqsOY{--shiki-light:#8796B0;--shiki-default:#B2CCD6;--shiki-dark:#B2CCD6}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":230,"searchDepth":231,"depth":231,"links":4956},[4957,4958,4959,4960,4961,4962,4968],{"id":288,"depth":234,"text":289},{"id":4056,"depth":234,"text":4057},{"id":4072,"depth":234,"text":4073},{"id":4094,"depth":234,"text":4095},{"id":4107,"depth":234,"text":4108},{"id":4297,"depth":234,"text":4298,"children":4963},[4964,4965,4966,4967],{"id":4304,"depth":507,"text":4305},{"id":4328,"depth":507,"text":4329},{"id":4416,"depth":507,"text":4417},{"id":4721,"depth":507,"text":4722},{"id":4930,"depth":234,"text":4931},"2025-11-19","Build a modern HMI using FlowFuse to monitor and control factory equipment from any browser","\u002Fblog\u002F2025\u002F11\u002Fimages\u002Fbuilding-a-web-hmi-for-factory.png",{"usecase":4973,"keywords":4975,"excerpt":4976},[4974],"production-monitoring","FlowFuse, web HMI, PLC control, Node-RED dashboard, industrial automation, edge device, MQTT, factory monitoring, SCADA alternative, remote equipment control",{"type":13,"value":4977},[4978],[16,4979,4016],{},"\u002Fblog\u002F2025\u002F11\u002Fbuilding-hmi-for-equipment-control",{"title":4010,"description":4970},{"loc":4980},"blog\u002F2025\u002F11\u002Fbuilding-hmi-for-equipment-control","Create web-based operator interfaces for industrial equipment",[1518,263],"dIFIM28NB1O5gSO9V4f9S9O3VFFtcBmHdW6gLnjBsuk",{"id":4988,"title":4989,"authors":4990,"body":4991,"cta":3,"date":5460,"description":5461,"extension":248,"image":5462,"lastUpdated":246,"meta":5463,"navigation":255,"path":5469,"seo":5470,"sitemap":5471,"stem":5472,"subtitle":5473,"tags":5474,"tldr":5477,"video":3,"__hash__":5478},"blog\u002Fblog\u002F2025\u002F10\u002Fplc-to-mqtt-using-flowfuse.md","How to Connect Any PLC to MQTT in Under an Hour",[11],{"type":13,"value":4992,"toc":5450},[4993,4996,4999,5002,5006,5009,5012,5015,5018,5021,5024,5026,5029,5043,5046,5049,5052,5055,5059,5062,5065,5068,5099,5108,5112,5118,5121,5132,5139,5142,5145,5149,5152,5157,5160,5163,5169,5175,5180,5189,5194,5197,5207,5212,5215,5222,5226,5229,5232,5235,5238,5246,5251,5265,5271,5274,5280,5285,5288,5291,5298,5301,5327,5332,5346,5349,5360,5368,5382,5390,5397,5405,5413,5417,5420,5423,5426,5429,5432,5436,5445],[16,4994,4995],{},"Getting PLC data into systems where it can be monitored, analyzed, and acted upon is essential for modern manufacturing. MQTT has become the standard for moving this data. It's lightweight, handles unreliable networks well, and excels at real-time streaming. Once your PLC data is published to MQTT, it creates a common pipeline that IT systems understand, flowing easily to cloud platforms, analytics tools, dashboards, and eliminating protocol translation headaches.",[16,4997,4998],{},"The protocol itself is simple. But implementation in a real factory, with actual PLCs and production networks, is where things fall apart. Costs pile up, timelines drag on, and you end up needing expertise that's hard to find.",[16,5000,5001],{},"This guide cuts through that complexity. You'll learn how to connect PLCs using MQTT without the typical headaches. We'll walk through extracting data from any PLC protocol, transforming it properly, and publishing it reliably, with working examples you can adapt to your own setup.",[26,5003,5005],{"id":5004},"why-plc-to-cloud-gets-so-complicated","Why PLC-to-Cloud Gets So Complicated",[16,5007,5008],{},"Before diving into the solution, it's worth understanding why this is so difficult.",[16,5010,5011],{},"First, there's the proprietary protocols. Factory floors have PLCs from different manufacturers, each speaking their own language: Modbus, OPC-UA, Ethernet\u002FIP, Profinet, FINS, etc. Getting data out means dealing with all of them at once, maintaining multiple drivers and troubleshooting different failure modes.",[16,5013,5014],{},"Then there's the networking challenge. Factory networks weren't built for internet connectivity. Isolated subnets, strict firewalls, and security-conscious IT departments mean getting approval for gateways (whether edge devices or software platforms) involves security reviews and architecture decisions that can drag on for months.",[16,5016,5017],{},"The costs add up quickly. Cloud platforms charge per message, and streaming data from dozens of machines easily reaches thousands per month, before gateway hardware and licenses.",[16,5019,5020],{},"And there's the expertise gap. Plant engineers know PLCs but not cloud APIs. IT teams know infrastructure but not industrial protocols. You end up needing expensive consultants, turning what should be straightforward into a six-figure project.",[16,5022,5023],{},"The solution lies in low-code integration platforms that consolidate protocol handling, edge computing, and cloud connectivity into a single system. This guide demonstrates one approach using FlowFuse, a platform built on Node-RED that addresses each challenge outlined above.",[26,5025,289],{"id":288},[16,5027,5028],{},"Before you start, make sure you have the following:",[53,5030,5031,5034],{},[56,5032,5033],{},"A properly configured and fully operational PLCs, located on the same network as the edge device that will be reading its data.",[56,5035,5036,5037,5042],{},"A running FlowFuse instance on your edge device. If you do not have an account, ",[105,5038,5041],{"href":5039,"rel":5040},"https:\u002F\u002Fflowfuse.com\u002Fblog\u002F2025\u002F09\u002Finstalling-node-red\u002F",[1240],"sign up for a free trial"," and set up your instance following the instructions in this article.",[5044,5045,2896],"h1",{"id":2895},[16,5047,5048],{},"Now, let's get started. First, watch this demo, where I have built a FlowFuse flow that collects data from four sources: Siemens S7 and Allen-Bradley PLCs, an OPC UA server, and a Modbus simulator.",[950,5050],{"videoid":5051,"params":2732,"style":2733,"title":2734},"vptAoDR78Cc",[16,5053,5054],{},"This flow standardizes data from each protocol into a consistent JSON format, enriches it with contextual metadata, and publishes everything to the FlowFuse MQTT Broker, all within a single instance. The following guide explains how to replicate this setup for any PLC on your factory floor.",[26,5056,5058],{"id":5057},"step-1-extract-data-from-your-plc","Step 1: Extract Data from Your PLC",[16,5060,5061],{},"As mentioned earlier, extracting data is the first and most complex step. Get this wrong, and the complexity and costs can spiral out of control. FlowFuse simplifies this process. Its pre-built connectors handle Modbus, OPC UA, EtherNet\u002FIP, and other protocols right out of the box, no custom coding, expensive proprietary gateways, or per-tag licensing fees required. You can configure your connections visually and have data flowing within minutes.",[16,5063,5064],{},"This is not just theory, Fortune 500 manufacturers are already running production systems on FlowFuse. Their consistent feedback? Massive cost savings compared to legacy systems, especially when deployed across multiple facilities. The enterprise features of FlowFuse handle the scale and security requirements large operations demand.",[16,5066,5067],{},"The Node-RED ecosystem that powers FlowFuse offers comprehensive protocol support. You'll find nodes available for every major PLC manufacturer, including:",[53,5069,5070,5074,5078,5083,5088,5092,5096],{},[56,5071,5072,4125],{},[349,5073,4124],{},[56,5075,5076,4133],{},[349,5077,2049],{},[56,5079,5080,5082],{},[349,5081,2387],{}," – OPC UA servers",[56,5084,5085,5087],{},[349,5086,4148],{}," – Allen-Bradley PLCs",[56,5089,5090,4159],{},[349,5091,4158],{},[56,5093,5094,4169],{},[349,5095,4168],{},[56,5097,5098],{},"and many more",[16,5100,5101,5102,5104,5105,5107],{},"Adding a protocol node to your FlowFuse instance takes just a few clicks. Open the palette manager from the hamburger menu, select ",[59,5103,2377],{},", go to the ",[59,5106,625],{}," tab, and search for the node you need.",[26,5109,5111],{"id":5110},"convincing-the-it-team","Convincing the IT Team",[16,5113,5114,5115,285],{},"When talking to people in the IIoT community, one recurring challenge always comes up, ",[59,5116,5117],{},"convincing the IT team",[16,5119,5120],{},"Traditional industrial gateways require inbound connections from the cloud. This means opening specific ports in your firewall, creating security exceptions, and giving external systems a pathway into your production network. IT security teams push back on this, and rightly so. Inbound connections expand your attack surface and violate the principle of defense in depth.",[16,5122,5123,5124,5127,5128,5131],{},"FlowFuse solves this with an ",[59,5125,5126],{},"edge-first architecture",". The Device Agent installs directly on hardware inside your factory network, a Raspberry Pi, an industrial PC, or even directly on supported PLCs. Once running, the agent initiates ",[59,5129,5130],{},"outbound"," connections to the FlowFuse platform using standard web protocols (HTTPS and WebSocket over port 443). All communication flows through this outbound connection. The platform never initiates connections back to your network.",[16,5133,5134,5135,5138],{},"From a security standpoint, this changes everything. Your firewall configuration does not change.",[5136,5137],"br",{},"\nNo new inbound rules. No DMZ setup. No VPN tunnels to maintain.",[16,5140,5141],{},"The device agent behaves like any other business application making secure outbound HTTPS requests, something your network already allows.",[16,5143,5144],{},"For networks with proxy servers, the agent supports standard proxy configurations through environment variables. For air-gapped networks, you can pre-cache Node-RED modules and deploy without internet connectivity after the initial setup.",[26,5146,5148],{"id":5147},"step-2-transform-and-structure-your-data","Step 2: Transform and Structure Your Data",[16,5150,5151],{},"Now let's move to the next step. Raw PLC data needs reshaping before cloud transmission. Register values, bit arrays, floating points, and timestamps arrive in different formats. FlowFuse offers several transformation methods suitable for different skill levels.",[16,5153,5154],{},[59,5155,5156],{},"Visual Transformation with Change Nodes and JSONata",[16,5158,5159],{},"Change nodes handle simple transformations without coding. They allow you to map fields, modify values, convert units, and add metadata using dropdowns and form fields. JSONata allows more advanced data manipulation directly within the Change node.",[16,5161,5162],{},"Plant engineers can work directly with these visual tools, no programming required.",[16,5164,5165,5166,5168],{},"For example, suppose you are receiving a pressure sensor value as ",[349,5167,2651],{}," but it lacks context.",[16,5170,5171,5172,5174],{},"You can use a ",[59,5173,3112],{}," node to:",[53,5176,5177],{},[56,5178,5179],{},"Add contextual information such as the machine ID, facility, or sensor location, unit",[16,5181,5182,5186],{},[650,5183],{"alt":5184,"dataZoomable":230,"src":5185},"Change node adding context to data","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fchange-node-adding-context.png",[1529,5187,5188],{},"Change node used to convert temperature and add machine context",[16,5190,5191],{},[59,5192,5193],{},"Function Nodes for Custom Logic",[16,5195,5196],{},"Function nodes provide full JavaScript access for complex requirements. Write custom logic, install npm packages, and access the complete JavaScript standard library when Change nodes and JSONata reach their limits.",[16,5198,5199],{},[1529,5200,5201,5202,5206],{},"Tip: Use the ",[105,5203,5205],{"href":5204},"\u002Fblog\u002F2025\u002F07\u002Fflowfuse-ai-assistant-better-node-red-manufacturing\u002F","FlowFuse Expert"," to generate function nodes. Describe the transformation you need in plain English, and it will create the code for you. For best results, provide sample input data to ensure the output matches your requirements.",[16,5208,5209],{},[59,5210,5211],{},"Pre-built Community Nodes",[16,5213,5214],{},"Before building custom solutions, check the palette manager. The Node-RED ecosystem includes thousands of nodes for data aggregation, statistical analysis, time-series buffering, and unit conversions. Many common transformation tasks already have ready-made solutions.",[16,5216,5217,5218,5221],{},"For example, a popular node I'm using in my demo for parsing and transforming data is ",[349,5219,5220],{},"node-red-contrib-buffer-parser",". This node is especially useful when working with Modbus or PLC outputs, as it converts raw data into structured formats that can be easily processed further.",[26,5223,5225],{"id":5224},"step-3-set-up-mqtt-with-flowfuse","Step 3: Set Up MQTT with FlowFuse",[16,5227,5228],{},"Most MQTT implementations require setting up a separate broker either paying for a managed service or hosting your own. FlowFuse includes a managed MQTT broker built directly into the platform, eliminating this extra step.",[16,5230,5231],{},"Traditional PLC-to-cloud setups typically involve several moving parts: edge gateways running protocol drivers, a separate MQTT broker (cloud-hosted or self-managed), and your destination cloud services. Each layer adds configuration work, licensing costs, and potential failure points. When data stops flowing, you end up troubleshooting across multiple systems to locate the issue.",[16,5233,5234],{},"FlowFuse consolidates those layers into a single integrated platform. It provides enterprise-grade features for management, scaling, deployment, and security, all handled by the FlowFuse infrastructure. You retain full control over configuration settings through a clean, intuitive interface, without needing to maintain multiple external systems.",[16,5236,5237],{},"To use the FlowFuse MQTT broker, you'll need a FlowFuse Pro or higher-tier account. Once on the Pro plan, you can enable the managed MQTT service by navigating to the Broker section from the left sidebar and selecting FlowFuse Broker.",[16,5239,5240,5244],{},[650,5241],{"alt":5242,"dataZoomable":230,"src":5243},"Enabling FlowFuse MQTT Broker","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fset-broker.png",[1529,5245,5242],{},[16,5247,5248],{},[59,5249,5250],{},"Configure Publishing",[472,5252,5253,5259,5262],{},[56,5254,932,5255,5258],{},[59,5256,5257],{},"FlowFuse MQTT Out"," node onto your canvas.",[56,5260,5261],{},"Open the node configuration. It will automatically pick up its configuration.",[56,5263,5264],{},"Set the topic following ISA-95 hierarchy:",[485,5266,5269],{"className":5267,"code":5268,"language":1327},[1325],"company\u002Fsite\u002Farea\u002Fline\u002Fcell\u002Fdevice\u002Fmeasurement\n",[349,5270,5268],{"__ignoreMap":230},[16,5272,5273],{},"For Example:",[485,5275,5278],{"className":5276,"code":5277,"language":1327},[1325],"acme\u002Fplant-a\u002Fassembly\u002Fline1\u002Fpress-1\u002Fpressure01\u002Fbar\n",[349,5279,5277],{"__ignoreMap":230},[16,5281,5282],{},[59,5283,5284],{},"Why ISA-95 for MQTT Topics",[16,5286,5287],{},"The ISA-95 Equipment Hierarchy Model is an international standard that defines how to organize manufacturing operations into logical layers. When you structure MQTT topics using this model, you're building toward a Unified Namespace (UNS), a single, consistent way to organize all operational data across your entire organization.",[16,5289,5290],{},"The goal of UNS is to eliminate data silos. Instead of each system maintaining its own proprietary structure, everything publishes to one shared namespace using a common hierarchy. Applications subscribe to exactly the data they need without knowing where it physically comes from or how it was collected.",[16,5292,5293,5294,5297],{},"ISA-95 makes this possible because it maps to how factories actually operate. ",[349,5295,5296],{},"company\u002Fsite\u002Farea\u002Fline\u002Fcell"," matches your organizational structure. When you expand to new facilities or add equipment, the hierarchy extends naturally. Analytics tools can compare performance across sites. MES systems subscribe to production line data. Dashboards pull from specific cells. Everything uses the same addressing scheme.",[16,5299,5300],{},"This enables powerful wildcard subscriptions:",[53,5302,5303,5309,5315,5321],{},[56,5304,5305,5308],{},[349,5306,5307],{},"acme\u002F#"," - all company data",[56,5310,5311,5314],{},[349,5312,5313],{},"acme\u002Fchicago\u002F#"," - single site",[56,5316,5317,5320],{},[349,5318,5319],{},"+\u002F+\u002Fassembly\u002F#"," - assembly operations everywhere",[56,5322,5323,5326],{},[349,5324,5325],{},"acme\u002Fchicago\u002Fassembly\u002Fline2\u002F#"," - one production line",[16,5328,5329],{},[1529,5330,5331],{},"Note: Use lowercase with hyphens for multi-word names.",[472,5333,5334,5342],{"start":231},[56,5335,2141,5336,989,5339,285],{},[59,5337,5338],{},"QoS",[59,5340,5341],{},"1",[56,5343,635,5344,285],{},[59,5345,853],{},[16,5347,5348],{},"After deploying the flow, the MQTT client for your device will be automatically created. To configure access:",[472,5350,5351,5354],{"start":524},[56,5352,5353],{},"Double-click the MQTT Out node.",[56,5355,635,5356,5359],{},[59,5357,5358],{},"Configure Access Control",". You will be redirected to the platform's broker client management section, filtered to show the client created for this instance.",[16,5361,5362,5366],{},[650,5363],{"alt":5364,"dataZoomable":230,"src":5365},"Configure MQTT Client Access Control","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fconfigure-access-control.png",[1529,5367,5364],{},[472,5369,5370],{"start":536},[56,5371,5372,5373,2465,5376,5378,5379,285],{},"Click the client ",[59,5374,5375],{},"edit",[59,5377,4843],{},", and then click ",[59,5380,5381],{},"Confirm",[16,5383,5384,5388],{},[650,5385],{"alt":5386,"dataZoomable":230,"src":5387},"Configuring Client Access Control","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fclient-access-control.jpg",[1529,5389,5364],{},[16,5391,5392,5393,5396],{},"That's it. You now have PLC data flowing to MQTT with proper access controls configured and a topic structure that scales with your organization. To view the topic hierarchy and the schema for your topics, go to the FlowFuse Broker section. Here, you'll see all the topics within your MQTT broker. By clicking ",[59,5394,5395],{},"Open Schema",", you can view the auto-generated schema document created by FlowFuse.",[16,5398,5399,5403],{},[650,5400],{"alt":5401,"dataZoomable":230,"src":5402},"FlowFuse Topic Hierarchy View","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fmqtt-topic-hierarchy.png",[1529,5404,5401],{},[16,5406,5407,5411],{},[650,5408],{"alt":5409,"dataZoomable":230,"src":5410},"Topic schema auto-generated by FlowFuse","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fmqtt-topic-schema-document.png",[1529,5412,5409],{},[26,5414,5416],{"id":5415},"bridging-the-expertise-gap-and-cutting-costs","Bridging the Expertise Gap and Cutting Costs",[16,5418,5419],{},"Now let's talk about the remaining problems: the expertise gap and cost. FlowFuse solves both by changing how the work gets done.",[16,5421,5422],{},"Plant engineers configure PLC connections, transform data, contextualize it, and send it to MQTT through drag-and-drop interfaces without writing code, that's what you saw in the steps above. IT teams manage security and access controls through standard web tools. Neither needs expertise in the other's domain.",[16,5424,5425],{},"The FlowFuse Expert fills remaining gaps, describe what you need in plain English, and it generates function nodes, database queries, or dashboard components. Click \"Explain\" on any flow to get instant documentation.",[16,5427,5428],{},"This eliminates the consultant dependency that inflates project costs. Your team handles implementation and maintenance without external help at $150-$250 per hour, saving $12,000 to $30,000 on setup alone. The managed MQTT broker includes unlimited messaging with no per-message fees. Protocol drivers are free and open-source with no per-tag licensing. Deploy on existing industrial hardware instead of buying $10,000 proprietary gateways.",[16,5430,5431],{},"Manufacturers typically see substantial cost reduction in the first year, with improving economics as you scale since hardware and licensing costs stay eliminated. Most engineers ship production flows in their first session.",[26,5433,5435],{"id":5434},"get-started","Get Started",[16,5437,5438,5439,5444],{},"Connect your first PLC today. ",[105,5440,5443],{"href":5441,"rel":5442},"https:\u002F\u002Fapp.flowfuse.com\u002F",[1240],"Sign up for FlowFuse",", install the Device Agent on your edge hardware, and have data flowing to MQTT in under an hour. The platform handles the complexity, you focus on turning factory data into insights.",[16,5446,5447,5448,285],{},"MQTT is one of several ways FlowFuse connects PLCs to the modern industrial stack. For a full view of supported protocols, OPC UA, EtherNet\u002FIP, Siemens S7, Modbus, and more, see the ",[105,5449,1475],{"href":1474},{"title":230,"searchDepth":231,"depth":231,"links":5451},[5452,5453,5454,5455,5456,5457,5458,5459],{"id":5004,"depth":234,"text":5005},{"id":288,"depth":234,"text":289},{"id":5057,"depth":234,"text":5058},{"id":5110,"depth":234,"text":5111},{"id":5147,"depth":234,"text":5148},{"id":5224,"depth":234,"text":5225},{"id":5415,"depth":234,"text":5416},{"id":5434,"depth":234,"text":5435},"2025-10-27","Learn how to extract data from Siemens, Allen-Bradley, Omron, Mitsubishi, OPC UA, and Modbus, transform it, and publish to MQTT using FlowFuse, without expensive gateways or consultants.","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fplc-to-mqtt.png",{"keywords":5464,"excerpt":5465},"MQTT, PLC, Siemens, S7, Allen-Bradley, EtherNet\u002FIP, Omron, FINS, Mitsubishi, MC Protocol, Modbus, Modbus-RTU, Modbus-TCP, OPC-UA, FlowFuse, Node-RED, Industrial IoT, IIoT",{"type":13,"value":5466},[5467],[16,5468,4995],{},"\u002Fblog\u002F2025\u002F10\u002Fplc-to-mqtt-using-flowfuse",{"title":4989,"description":5461},{"loc":5469},"blog\u002F2025\u002F10\u002Fplc-to-mqtt-using-flowfuse","Connect any PLC to MQTT without the typical complexity, costs, and expertise requirements",[1518,5475,5476,263],"modbus","mqtt","This tutorial shows how to publish PLC data to MQTT using FlowFuse and Node-RED without expensive gateways or consultants. You extract data from any PLC protocol (Modbus, OPC UA, EtherNet\u002FIP, Siemens S7, and more) using pre-built connectors, transform and contextualize it into consistent JSON with Change, Function, or community nodes, then publish it to the built-in FlowFuse MQTT broker using an ISA-95 topic hierarchy with proper access controls. FlowFuse's edge-first architecture keeps firewalls closed to inbound traffic, letting plant engineers ship production flows in under an hour.","iXlNoqWxawYlRLfLHSUTlUMBAtOb9J8uyDRM0dnYmlI",{"id":5480,"title":5481,"authors":5482,"body":5483,"cta":3,"date":6694,"description":6695,"extension":248,"image":6696,"lastUpdated":3,"meta":6697,"navigation":255,"path":6703,"seo":6704,"sitemap":6705,"stem":6706,"subtitle":6707,"tags":6708,"tldr":3,"video":3,"__hash__":6709},"blog\u002Fblog\u002F2025\u002F10\u002Fhow-to-log-plc-data-csv-files.md","How to Log PLC Data to CSV Files",[11],{"type":13,"value":5484,"toc":6676},[5485,5488,5491,5494,5497,5503,5511,5513,5516,5524,5528,5531,5535,5538,5541,5547,5558,5562,5565,5593,5596,5599,5602,5606,5609,5612,5615,5618,5622,5625,5629,5632,5646,5650,5653,5664,5942,5947,5957,5961,5964,5993,6001,6004,6008,6011,6041,6049,6052,6055,6059,6062,6065,6073,6530,6550,6553,6557,6560,6563,6576,6579,6584,6642,6644,6647,6650,6653,6656,6659,6664,6673],[16,5486,5487],{},"CSV files have been recording manufacturing data since the mid-1980s, over 40 years of continuous use across every industry. Logging to databases like InfluxDB, TimescaleDB, or PostgreSQL is excellent for real-time analytics, complex queries, and large-scale operations. But many organizations still rely on CSV files for good reasons: regulatory compliance, legacy system integration, offline analysis, or simply because it's the format their teams know and trust. If you're reading this, you're likely one of them and need a reliable solution.",[16,5489,5490],{},"CSV files offer something databases can't always guarantee: universal compatibility and permanence. Excel opens them instantly, databases import them natively, and analysis tools expect them. No licensing, no vendor tie-ins, no format obsolescence. Data captured decades ago is still perfectly readable today and will be readable decades from now, regardless of what systems you're using.",[16,5492,5493],{},"The truth is, most manufacturers use both for distinct purposes. CSVs remain the standard on the shop floor for data loggers that write locally during network outages, regulatory submissions requiring immutable audit trails, batch documentation archived for decades, and data exchange with suppliers and auditors.",[16,5495,5496],{},"Meanwhile, databases handle real-time monitoring and automated alerts, cross-functional analytics, high-frequency sensor queries, and dynamic relationships across materials and equipment.",[16,5498,5499,5500,5502],{},"This isn't an either\u002For choice. It's a dual-track system where databases provide operational speed and CSVs provide the permanence layer, ensuring your compliance records and critical data outlive any technology stack.\nThis guide shows how to implement PLC data logging with ",[59,5501,284],{}," in a way that keeps running, stable, resilient, and production-ready.",[16,5504,5505,5509],{},[650,5506],{"alt":5507,"dataZoomable":230,"src":5508},"Image showing FlowFuse collecting data from a PLC using OPC UA and logging it to a CSV file.","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fplc-to-csv.gif",[1529,5510,5507],{},[26,5512,289],{"id":288},[16,5514,5515],{},"Before getting started, make sure you have:",[53,5517,5518],{},[56,5519,5520,5523],{},[59,5521,5522],{},"A running FlowFuse instance"," – If you don’t have one yet, [sign up]({% include \"sign-up-url.njk\" %}) for FlowFuse and set up an instance on your edge device. This device will manage data collection and logging from your PLC using Node-RED.",[26,5525,5527],{"id":5526},"step-1-setting-up-plc-communication-in-flowfuse","Step 1: Setting Up PLC Communication in FlowFuse",[16,5529,5530],{},"Before logging data, you need a stable connection to your PLC. FlowFuse uses Node-RED under the hood, which supports every major industrial protocol through community-maintained packages. This means you can connect to any equipment, regardless of age or manufacturer.",[1224,5532,5534],{"id":5533},"choosing-your-protocol","Choosing Your Protocol",[16,5536,5537],{},"The right protocol depends on what your PLC supports.",[16,5539,5540],{},"Modern PLCs typically offer open standards like OPC UA, Modbus TCP, or EtherNet\u002FIP. These protocols work across different manufacturers and give you the most flexibility.",[16,5542,5543,5544,285],{},"If your PLC supports OPC UA, that is likely your best option. It is becoming the common language across industrial equipment, Siemens, Rockwell, Schneider, and most other manufacturers support it. This is also the option I used in the demo I prepared for this article. For more information on how to use OPC UA with your PLC, you can refer to ",[105,5545,5546],{"href":2660},"this article",[16,5548,5549,5550,5553,5554,5557],{},"Legacy systems use vendor-specific protocols: ",[105,5551,5552],{"href":4132},"S7"," for Siemens, MC Protocol for Mitsubishi, FINS for Omron, and ",[105,5555,5556],{"href":4147},"EtherNet\u002FIP"," for Allen-Bradley. If your PLC only speaks its native language, Node-RED has dedicated nodes for each one.",[1224,5559,5561],{"id":5560},"installing-the-right-node","Installing the Right Node",[16,5563,5564],{},"Node-RED's package ecosystem includes nodes for virtually every industrial protocol. The most common ones are:",[53,5566,5567,5572,5576,5580,5584,5589],{},[56,5568,5569,5571],{},[349,5570,4124],{}," – Modbus RTU\u002FTCP devices",[56,5573,5574,4133],{},[349,5575,2049],{},[56,5577,5578,5082],{},[349,5579,2387],{},[56,5581,5582,5087],{},[349,5583,4148],{},[56,5585,5586,5588],{},[349,5587,4158],{}," – Mitsubishi Q\u002FL series",[56,5590,5591,4169],{},[349,5592,4168],{},[16,5594,5595],{},"To install a package in FlowFuse, go to the palette manager (hamburger menu → Manage palette → Install) and search for the node you need. Installation takes seconds.",[1224,5597,4211],{"id":5598},"configuring-your-connection",[16,5600,5601],{},"Drag the appropriate input node onto your canvas and configure it according to the node's documentation.",[1224,5603,5605],{"id":5604},"verifying-data-quality","Verifying Data Quality",[16,5607,5608],{},"Before building your logging flow, verify you're getting clean, consistent data. Connect a debug node to your PLC input, deploy, and watch the incoming messages.",[16,5610,5611],{},"You should see values updating at your configured interval with consistent structure and sensible numbers. No connection errors, timeouts, or garbage data.",[16,5613,5614],{},"If something's wrong, intermittent connections, bad values, protocol errors, fix it now. Connection problems multiply when you add logging logic on top.",[16,5616,5617],{},"A stable PLC connection is the foundation. Get this right, and the rest is straightforward.",[26,5619,5621],{"id":5620},"step-2-building-the-basic-csv-logging-flow","Step 2: Building the Basic CSV Logging Flow",[16,5623,5624],{},"With a stable PLC connection verified, you can now build the flow that writes data to CSV files.",[1224,5626,5628],{"id":5627},"understanding-the-data-flow","Understanding the Data Flow",[16,5630,5631],{},"The logging system needs four components working together:",[472,5633,5634,5637,5640,5643],{},[56,5635,5636],{},"PLC input node that collects data at regular intervals",[56,5638,5639],{},"Function node that adds timestamps and handles daily file rotation",[56,5641,5642],{},"CSV node that formats data into proper CSV structure",[56,5644,5645],{},"File node that writes to disk",[1224,5647,5649],{"id":5648},"adding-timestamps-and-daily-file-rotation","Adding Timestamps and Daily File Rotation",[16,5651,5652],{},"Your PLC data needs timestamps and a way to organize files by date.",[472,5654,5655,5658,5661],{},[56,5656,5657],{},"Drag a function node onto your canvas",[56,5659,5660],{},"Connect it to your PLC input node",[56,5662,5663],{},"Double-click the function node and add this code:",[485,5665,5669],{"className":5666,"code":5667,"language":5668,"meta":230,"style":230},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const now = new Date();\nconst timestamp = now.toISOString();\n\n\u002F\u002F Create filename with today's date (YYYY-MM-DD format)\nconst dateStr = now.toISOString().split('T')[0];\nconst filename = `.\u002Fplc_data_${dateStr}.csv`;\n\n\u002F\u002F Structure the data\nmsg.payload = {\n    timestamp: timestamp,\n    temperature: msg.payload.temperature,\n    pressure: msg.payload.pressure,\n    flowRate: msg.payload.flowRate\n};\n\n\u002F\u002F Store filename for the file node\nmsg.filename = filename;\n\nreturn msg;\n","javascript",[349,5670,5671,5695,5716,5720,5726,5770,5802,5806,5811,5825,5839,5860,5880,5898,5903,5907,5912,5928,5932],{"__ignoreMap":230},[493,5672,5673,5677,5680,5683,5686,5690,5693],{"class":495,"line":496},[493,5674,5676],{"class":5675},"spNyl","const",[493,5678,5679],{"class":4605}," now ",[493,5681,5682],{"class":4586},"=",[493,5684,5685],{"class":4586}," new",[493,5687,5689],{"class":5688},"s2Zo4"," Date",[493,5691,5692],{"class":4605},"()",[493,5694,4613],{"class":4586},[493,5696,5697,5699,5702,5704,5707,5709,5712,5714],{"class":495,"line":234},[493,5698,5676],{"class":5675},[493,5700,5701],{"class":4605}," timestamp ",[493,5703,5682],{"class":4586},[493,5705,5706],{"class":4605}," now",[493,5708,285],{"class":4586},[493,5710,5711],{"class":5688},"toISOString",[493,5713,5692],{"class":4605},[493,5715,4613],{"class":4586},[493,5717,5718],{"class":495,"line":507},[493,5719,2771],{"emptyLinePlaceholder":255},[493,5721,5722],{"class":495,"line":231},[493,5723,5725],{"class":5724},"sHwdD","\u002F\u002F Create filename with today's date (YYYY-MM-DD format)\n",[493,5727,5728,5730,5733,5735,5737,5739,5741,5743,5745,5748,5751,5754,5758,5760,5763,5765,5768],{"class":495,"line":518},[493,5729,5676],{"class":5675},[493,5731,5732],{"class":4605}," dateStr ",[493,5734,5682],{"class":4586},[493,5736,5706],{"class":4605},[493,5738,285],{"class":4586},[493,5740,5711],{"class":5688},[493,5742,5692],{"class":4605},[493,5744,285],{"class":4586},[493,5746,5747],{"class":5688},"split",[493,5749,5750],{"class":4605},"(",[493,5752,5753],{"class":4586},"'",[493,5755,5757],{"class":5756},"sfazB","T",[493,5759,5753],{"class":4586},[493,5761,5762],{"class":4605},")[",[493,5764,401],{"class":4609},[493,5766,5767],{"class":4605},"]",[493,5769,4613],{"class":4586},[493,5771,5772,5774,5777,5779,5782,5785,5788,5791,5794,5797,5800],{"class":495,"line":524},[493,5773,5676],{"class":5675},[493,5775,5776],{"class":4605}," filename ",[493,5778,5682],{"class":4586},[493,5780,5781],{"class":4586}," `",[493,5783,5784],{"class":5756},".\u002Fplc_data_",[493,5786,5787],{"class":4586},"${",[493,5789,5790],{"class":4605},"dateStr",[493,5792,5793],{"class":4586},"}",[493,5795,5796],{"class":5756},".csv",[493,5798,5799],{"class":4586},"`",[493,5801,4613],{"class":4586},[493,5803,5804],{"class":495,"line":530},[493,5805,2771],{"emptyLinePlaceholder":255},[493,5807,5808],{"class":495,"line":536},[493,5809,5810],{"class":5724},"\u002F\u002F Structure the data\n",[493,5812,5813,5816,5818,5821,5823],{"class":495,"line":542},[493,5814,5815],{"class":4605},"msg",[493,5817,285],{"class":4586},[493,5819,5820],{"class":4605},"payload ",[493,5822,5682],{"class":4586},[493,5824,4593],{"class":4586},[493,5826,5827,5831,5833,5836],{"class":495,"line":548},[493,5828,5830],{"class":5829},"swJcz","    timestamp",[493,5832,4602],{"class":4586},[493,5834,5835],{"class":4605}," timestamp",[493,5837,5838],{"class":4586},",\n",[493,5840,5841,5844,5846,5849,5851,5854,5856,5858],{"class":495,"line":554},[493,5842,5843],{"class":5829},"    temperature",[493,5845,4602],{"class":4586},[493,5847,5848],{"class":4605}," msg",[493,5850,285],{"class":4586},[493,5852,5853],{"class":4605},"payload",[493,5855,285],{"class":4586},[493,5857,1346],{"class":4605},[493,5859,5838],{"class":4586},[493,5861,5862,5865,5867,5869,5871,5873,5875,5878],{"class":495,"line":560},[493,5863,5864],{"class":5829},"    pressure",[493,5866,4602],{"class":4586},[493,5868,5848],{"class":4605},[493,5870,285],{"class":4586},[493,5872,5853],{"class":4605},[493,5874,285],{"class":4586},[493,5876,5877],{"class":4605},"pressure",[493,5879,5838],{"class":4586},[493,5881,5882,5885,5887,5889,5891,5893,5895],{"class":495,"line":566},[493,5883,5884],{"class":5829},"    flowRate",[493,5886,4602],{"class":4586},[493,5888,5848],{"class":4605},[493,5890,285],{"class":4586},[493,5892,5853],{"class":4605},[493,5894,285],{"class":4586},[493,5896,5897],{"class":4605},"flowRate\n",[493,5899,5900],{"class":495,"line":572},[493,5901,5902],{"class":4586},"};\n",[493,5904,5905],{"class":495,"line":578},[493,5906,2771],{"emptyLinePlaceholder":255},[493,5908,5909],{"class":495,"line":2827},[493,5910,5911],{"class":5724},"\u002F\u002F Store filename for the file node\n",[493,5913,5914,5916,5918,5921,5923,5926],{"class":495,"line":2832},[493,5915,5815],{"class":4605},[493,5917,285],{"class":4586},[493,5919,5920],{"class":4605},"filename ",[493,5922,5682],{"class":4586},[493,5924,5925],{"class":4605}," filename",[493,5927,4613],{"class":4586},[493,5929,5930],{"class":495,"line":2838},[493,5931,2771],{"emptyLinePlaceholder":255},[493,5933,5934,5938,5940],{"class":495,"line":2844},[493,5935,5937],{"class":5936},"s7zQu","return",[493,5939,5848],{"class":4605},[493,5941,4613],{"class":4586},[472,5943,5944],{"start":231},[56,5945,5946],{},"Click Done",[16,5948,5949,5950,1447,5953,5956],{},"This creates a new file each day automatically. When the date changes, the filename changes, and Node-RED starts writing to a fresh file. Your logs stay organized by date: ",[349,5951,5952],{},"plc_data_2025-10-16.csv",[349,5954,5955],{},"plc_data_2025-10-17.csv",", and so on.",[1224,5958,5960],{"id":5959},"formatting-data-with-the-csv-node","Formatting Data with the CSV Node",[16,5962,5963],{},"The CSV node handles all the formatting work, proper escaping, column ordering, and headers.",[472,5965,5966,5969,5972,5991],{},[56,5967,5968],{},"Drag a CSV node onto your canvas",[56,5970,5971],{},"Connect it to your function node",[56,5973,4513,5974],{},[53,5975,5976,5982,5985,5988],{},[56,5977,5978,5979],{},"Set the columns: ",[349,5980,5981],{},"timestamp,temperature",[56,5983,5984],{},"Enable \"first row contains column names\"",[56,5986,5987],{},"Choose comma as the separator",[56,5989,5990],{},"Choose RFC 4180 as parser (this handles commas in your data, like alarm messages or status text, by wrapping them in quotes so they don't break the CSV structure)",[56,5992,5946],{},[16,5994,5995,5999],{},[650,5996],{"alt":5997,"dataZoomable":230,"src":5998},"Image showing CSV node configuration","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fcsv-config.png",[1529,6000,5997],{},[16,6002,6003],{},"The CSV node converts your data object into a properly formatted CSV line with headers included automatically when a new file is created.",[1224,6005,6007],{"id":6006},"writing-to-file","Writing to File",[16,6009,6010],{},"The file node writes your formatted CSV data to disk.",[472,6012,6013,6016,6019,6036,6038],{},[56,6014,6015],{},"Drag a file node onto your canvas",[56,6017,6018],{},"Connect it to your CSV node",[56,6020,4513,6021],{},[53,6022,6023,6030,6033],{},[56,6024,6025,6026,6029],{},"Set filename to ",[349,6027,6028],{},"msg.filename"," (uses the dynamic filename from your function)",[56,6031,6032],{},"Choose \"append to file\" mode",[56,6034,6035],{},"Enable \"Create directory if it doesn't exist\"",[56,6037,5946],{},[56,6039,6040],{},"Deploy your flow",[16,6042,6043,6047],{},[650,6044],{"alt":6045,"dataZoomable":230,"src":6046},"Image showing Write node configuration","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fwrite-file-config.png",[1529,6048,6045],{},[16,6050,6051],{},"Let it run. Each day at midnight, the system automatically starts a new file. Old files stay untouched, new data goes to today's file.",[16,6053,6054],{},"This daily rotation keeps file sizes manageable and makes it easy to find data from specific dates. But there are still edge cases to handle, what happens when disk space runs low or file writes fail? The next step addresses these reliability issues.",[26,6056,6058],{"id":6057},"step-3-monitoring-disk-usage","Step 3: Monitoring Disk Usage",[16,6060,6061],{},"Running a logging system continuously means files accumulate. Monitor disk space to prevent unexpected failures when storage runs low.",[16,6063,6064],{},"Add disk space monitoring to prevent unexpected failures.",[472,6066,6067,6070],{},[56,6068,6069],{},"Drag an inject node onto your canvas and configure it to trigger every hour",[56,6071,6072],{},"Add a Function node with the following code. Since the code uses the fs module, make sure to import it within the setup of function node:",[485,6074,6076],{"className":5666,"code":6075,"language":5668,"meta":230,"style":230},"try {\n    \u002F\u002F Get disk usage information\n    const stats = fs.statfsSync('.\u002F');\n\n    const totalSpace = stats.blocks * stats.bsize;\n    const freeSpace = stats.bfree * stats.bsize;\n    const usedSpace = totalSpace - freeSpace;\n    const percentUsed = (usedSpace \u002F totalSpace) * 100;\n\n    msg.payload = {\n        totalGB: (totalSpace \u002F (1024 ** 3)).toFixed(2),\n        freeGB: (freeSpace \u002F (1024 ** 3)).toFixed(2),\n        usedGB: (usedSpace \u002F (1024 ** 3)).toFixed(2),\n        percentUsed: percentUsed.toFixed(2)\n    };\n\n    \u002F\u002F Warning threshold\n    if (percentUsed > 90) {\n        msg.warning = `Disk space critical: ${percentUsed.toFixed(1)}% used`;\n    }\n\n    return msg;\n\n} catch (err) {\n    msg.payload = { error: err.message };\n    return msg;\n}\n",[349,6077,6078,6085,6090,6122,6126,6154,6180,6198,6229,6233,6246,6288,6324,6359,6379,6384,6388,6393,6414,6454,6459,6463,6472,6476,6488,6517,6525],{"__ignoreMap":230},[493,6079,6080,6083],{"class":495,"line":496},[493,6081,6082],{"class":5936},"try",[493,6084,4593],{"class":4586},[493,6086,6087],{"class":495,"line":234},[493,6088,6089],{"class":5724},"    \u002F\u002F Get disk usage information\n",[493,6091,6092,6095,6098,6101,6104,6106,6109,6111,6113,6116,6118,6120],{"class":495,"line":507},[493,6093,6094],{"class":5675},"    const",[493,6096,6097],{"class":4605}," stats",[493,6099,6100],{"class":4586}," =",[493,6102,6103],{"class":4605}," fs",[493,6105,285],{"class":4586},[493,6107,6108],{"class":5688},"statfsSync",[493,6110,5750],{"class":5829},[493,6112,5753],{"class":4586},[493,6114,6115],{"class":5756},".\u002F",[493,6117,5753],{"class":4586},[493,6119,2445],{"class":5829},[493,6121,4613],{"class":4586},[493,6123,6124],{"class":495,"line":231},[493,6125,2771],{"emptyLinePlaceholder":255},[493,6127,6128,6130,6133,6135,6137,6139,6142,6145,6147,6149,6152],{"class":495,"line":518},[493,6129,6094],{"class":5675},[493,6131,6132],{"class":4605}," totalSpace",[493,6134,6100],{"class":4586},[493,6136,6097],{"class":4605},[493,6138,285],{"class":4586},[493,6140,6141],{"class":4605},"blocks",[493,6143,6144],{"class":4586}," *",[493,6146,6097],{"class":4605},[493,6148,285],{"class":4586},[493,6150,6151],{"class":4605},"bsize",[493,6153,4613],{"class":4586},[493,6155,6156,6158,6161,6163,6165,6167,6170,6172,6174,6176,6178],{"class":495,"line":524},[493,6157,6094],{"class":5675},[493,6159,6160],{"class":4605}," freeSpace",[493,6162,6100],{"class":4586},[493,6164,6097],{"class":4605},[493,6166,285],{"class":4586},[493,6168,6169],{"class":4605},"bfree",[493,6171,6144],{"class":4586},[493,6173,6097],{"class":4605},[493,6175,285],{"class":4586},[493,6177,6151],{"class":4605},[493,6179,4613],{"class":4586},[493,6181,6182,6184,6187,6189,6191,6194,6196],{"class":495,"line":530},[493,6183,6094],{"class":5675},[493,6185,6186],{"class":4605}," usedSpace",[493,6188,6100],{"class":4586},[493,6190,6132],{"class":4605},[493,6192,6193],{"class":4586}," -",[493,6195,6160],{"class":4605},[493,6197,4613],{"class":4586},[493,6199,6200,6202,6205,6207,6210,6213,6216,6218,6221,6224,6227],{"class":495,"line":536},[493,6201,6094],{"class":5675},[493,6203,6204],{"class":4605}," percentUsed",[493,6206,6100],{"class":4586},[493,6208,6209],{"class":5829}," (",[493,6211,6212],{"class":4605},"usedSpace",[493,6214,6215],{"class":4586}," \u002F",[493,6217,6132],{"class":4605},[493,6219,6220],{"class":5829},") ",[493,6222,6223],{"class":4586},"*",[493,6225,6226],{"class":4609}," 100",[493,6228,4613],{"class":4586},[493,6230,6231],{"class":495,"line":542},[493,6232,2771],{"emptyLinePlaceholder":255},[493,6234,6235,6238,6240,6242,6244],{"class":495,"line":548},[493,6236,6237],{"class":4605},"    msg",[493,6239,285],{"class":4586},[493,6241,5853],{"class":4605},[493,6243,6100],{"class":4586},[493,6245,4593],{"class":4586},[493,6247,6248,6251,6253,6255,6258,6260,6262,6265,6268,6271,6274,6276,6279,6281,6284,6286],{"class":495,"line":554},[493,6249,6250],{"class":5829},"        totalGB",[493,6252,4602],{"class":4586},[493,6254,6209],{"class":5829},[493,6256,6257],{"class":4605},"totalSpace",[493,6259,6215],{"class":4586},[493,6261,6209],{"class":5829},[493,6263,6264],{"class":4609},"1024",[493,6266,6267],{"class":4586}," **",[493,6269,6270],{"class":4609}," 3",[493,6272,6273],{"class":5829},"))",[493,6275,285],{"class":4586},[493,6277,6278],{"class":5688},"toFixed",[493,6280,5750],{"class":5829},[493,6282,6283],{"class":4609},"2",[493,6285,2445],{"class":5829},[493,6287,5838],{"class":4586},[493,6289,6290,6293,6295,6297,6300,6302,6304,6306,6308,6310,6312,6314,6316,6318,6320,6322],{"class":495,"line":560},[493,6291,6292],{"class":5829},"        freeGB",[493,6294,4602],{"class":4586},[493,6296,6209],{"class":5829},[493,6298,6299],{"class":4605},"freeSpace",[493,6301,6215],{"class":4586},[493,6303,6209],{"class":5829},[493,6305,6264],{"class":4609},[493,6307,6267],{"class":4586},[493,6309,6270],{"class":4609},[493,6311,6273],{"class":5829},[493,6313,285],{"class":4586},[493,6315,6278],{"class":5688},[493,6317,5750],{"class":5829},[493,6319,6283],{"class":4609},[493,6321,2445],{"class":5829},[493,6323,5838],{"class":4586},[493,6325,6326,6329,6331,6333,6335,6337,6339,6341,6343,6345,6347,6349,6351,6353,6355,6357],{"class":495,"line":566},[493,6327,6328],{"class":5829},"        usedGB",[493,6330,4602],{"class":4586},[493,6332,6209],{"class":5829},[493,6334,6212],{"class":4605},[493,6336,6215],{"class":4586},[493,6338,6209],{"class":5829},[493,6340,6264],{"class":4609},[493,6342,6267],{"class":4586},[493,6344,6270],{"class":4609},[493,6346,6273],{"class":5829},[493,6348,285],{"class":4586},[493,6350,6278],{"class":5688},[493,6352,5750],{"class":5829},[493,6354,6283],{"class":4609},[493,6356,2445],{"class":5829},[493,6358,5838],{"class":4586},[493,6360,6361,6364,6366,6368,6370,6372,6374,6376],{"class":495,"line":572},[493,6362,6363],{"class":5829},"        percentUsed",[493,6365,4602],{"class":4586},[493,6367,6204],{"class":4605},[493,6369,285],{"class":4586},[493,6371,6278],{"class":5688},[493,6373,5750],{"class":5829},[493,6375,6283],{"class":4609},[493,6377,6378],{"class":5829},")\n",[493,6380,6381],{"class":495,"line":578},[493,6382,6383],{"class":4586},"    };\n",[493,6385,6386],{"class":495,"line":2827},[493,6387,2771],{"emptyLinePlaceholder":255},[493,6389,6390],{"class":495,"line":2832},[493,6391,6392],{"class":5724},"    \u002F\u002F Warning threshold\n",[493,6394,6395,6398,6400,6403,6406,6409,6411],{"class":495,"line":2838},[493,6396,6397],{"class":5936},"    if",[493,6399,6209],{"class":5829},[493,6401,6402],{"class":4605},"percentUsed",[493,6404,6405],{"class":4586}," >",[493,6407,6408],{"class":4609}," 90",[493,6410,6220],{"class":5829},[493,6412,6413],{"class":4586},"{\n",[493,6415,6416,6419,6421,6424,6426,6428,6431,6433,6435,6437,6439,6441,6443,6445,6447,6450,6452],{"class":495,"line":2844},[493,6417,6418],{"class":4605},"        msg",[493,6420,285],{"class":4586},[493,6422,6423],{"class":4605},"warning",[493,6425,6100],{"class":4586},[493,6427,5781],{"class":4586},[493,6429,6430],{"class":5756},"Disk space critical: ",[493,6432,5787],{"class":4586},[493,6434,6402],{"class":4605},[493,6436,285],{"class":4586},[493,6438,6278],{"class":5688},[493,6440,5750],{"class":4605},[493,6442,5341],{"class":4609},[493,6444,2445],{"class":4605},[493,6446,5793],{"class":4586},[493,6448,6449],{"class":5756},"% used",[493,6451,5799],{"class":4586},[493,6453,4613],{"class":4586},[493,6455,6456],{"class":495,"line":2850},[493,6457,6458],{"class":4586},"    }\n",[493,6460,6461],{"class":495,"line":2856},[493,6462,2771],{"emptyLinePlaceholder":255},[493,6464,6465,6468,6470],{"class":495,"line":2862},[493,6466,6467],{"class":5936},"    return",[493,6469,5848],{"class":4605},[493,6471,4613],{"class":4586},[493,6473,6474],{"class":495,"line":2868},[493,6475,2771],{"emptyLinePlaceholder":255},[493,6477,6478,6480,6483,6486],{"class":495,"line":2874},[493,6479,5793],{"class":4586},[493,6481,6482],{"class":5936}," catch",[493,6484,6485],{"class":4605}," (err) ",[493,6487,6413],{"class":4586},[493,6489,6490,6492,6494,6496,6498,6501,6504,6506,6509,6511,6514],{"class":495,"line":2880},[493,6491,6237],{"class":4605},[493,6493,285],{"class":4586},[493,6495,5853],{"class":4605},[493,6497,6100],{"class":4586},[493,6499,6500],{"class":4586}," {",[493,6502,6503],{"class":5829}," error",[493,6505,4602],{"class":4586},[493,6507,6508],{"class":4605}," err",[493,6510,285],{"class":4586},[493,6512,6513],{"class":4605},"message",[493,6515,6516],{"class":4586}," };\n",[493,6518,6519,6521,6523],{"class":495,"line":2886},[493,6520,6467],{"class":5936},[493,6522,5848],{"class":4605},[493,6524,4613],{"class":4586},[493,6526,6528],{"class":495,"line":6527},27,[493,6529,4645],{"class":4586},[472,6531,6532,6547],{"start":507},[56,6533,6534,6535,1447,6539,6543,6544,285],{},"Connect it to your notification system to alert when space is critical, for notification you can use ",[105,6536,6538],{"href":6537},"\u002Fnode-red\u002Fnotification\u002Femail\u002F","email",[105,6540,6542],{"href":6541},"\u002Fnode-red\u002Fnotification\u002Ftelegram\u002F","telegram",", discord with ",[105,6545,284],{"href":6546},"\u002Fnode-red\u002Fnotification\u002Fdiscord\u002F",[56,6548,6549],{},"Deploy the flow",[16,6551,6552],{},"Now you'll get warnings before disk space becomes critical, giving you time to archive old data or expand storage.",[26,6554,6556],{"id":6555},"step-4-handling-connection-interruptions","Step 4: Handling Connection Interruptions",[16,6558,6559],{},"Network issues, PLC restarts, or equipment maintenance can cause connection drops. Your logging system should handle these gracefully and automatically resume when the connection is restored.",[16,6561,6562],{},"Most PLC nodes emit error events when a connection fails. Add error handling to detect and log these events.",[472,6564,6565,6568,6571,6574],{},[56,6566,6567],{},"Add a Catch node configured to monitor your PLC input node and Write File node.",[56,6569,6570],{},"Drag a Function or Change node to format the error messages according to your chosen notification method, and connect it to the Catch node.",[56,6572,6573],{},"Connect the node that formats the error message to your selected Notification node.",[56,6575,3711],{},[16,6577,6578],{},"Below is the complete flow we have built throughout this article.",[16,6580,6581],{},[1529,6582,6583],{},"Note: When testing with the Inject node, bypass the OPC UA Client and inject data directly into the logger flow.",[16,6585,6586,6587,6641],{},"{% renderFlow 300 %}\n",[493,6588,6589,6590,6593,6594,6596,6597,6600,6601,6603,6604,3269,6606,6608,6609,6612,6613,6616,6617,6619,6620,6623,6624,6627,6628,6631,6632,6634,6635,6637,6638,6640],{},"{\"id\":\"66776385db5794bc\",\"type\":\"group\",\"z\":\"FFF0000000000001\",\"name\":\"\",\"style\":{\"fill\":\"#ffcf3f\",\"label\":true,\"fill-opacity\":\"0.57\"},\"nodes\":",[493,6591,6592],{},"\"ac0d35a6466cfcb4\",\"4aff5b57cbb63b8f\",\"a5c5746934670306\",\"d796d3aee8ea0343\",\"23ebc0da4315ac46\",\"181ed86f9c11d1f7\",\"b34d440897108110\",\"575ed67714072973\",\"d08353a9c90b0396\",\"e719ae6fee22c812\",\"2518dc909d447655\"",",\"x\":94,\"y\":271.5,\"w\":1112,\"h\":269.5},{\"id\":\"ac0d35a6466cfcb4\",\"type\":\"csv\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"\",\"spec\":\"rfc\",\"sep\":\",\",\"hdrin\":true,\"hdrout\":\"once\",\"multi\":\"one\",\"ret\":\"\\r\",\"temp\":\"timestamp,temperature\",\"skip\":\"0\",\"strings\":true,\"include_empty_strings\":\"\",\"include_null_values\":\"\",\"x\":770,\"y\":320,\"wires\":[[\"a5c5746934670306\"]]},{\"id\":\"4aff5b57cbb63b8f\",\"type\":\"function\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"Daily PLC Logger\",\"func\":\"\u002F\u002F @ts-ignore Node ≥ 18.15 provides fs.statfsSync; editor types may lag\\n\\nconst now = new Date();\\nconst dateStr = now.toISOString().split('T')",[493,6595,401],{},";\\nconst timestamp = now.toISOString();\\n\\nconst filename = ",[349,6598,6599],{},".\u002Fplc_data_${dateStr}.csv",";\\n\\nmsg.payload = {\\n    timestamp: timestamp,\\n    temperature: msg.payload,\\n};\\n\\nmsg.filename = filename;\\n\\n\u002F\u002F Track last date in flow context\\nconst lastDate = flow.get('lastDate') || '';\\nif (lastDate !== dateStr) {\\n    msg.reset = true; \u002F\u002F Will trigger CSV node to write headers\\n    flow.set('lastDate', dateStr);\\n} \\n\\nreturn msg;\\n\",\"outputs\":1,\"timeout\":0,\"noerr\":0,\"initialize\":\"\",\"finalize\":\"\",\"libs\":",[493,6602],{},",\"x\":610,\"y\":320,\"wires\":[[\"ac0d35a6466cfcb4\"]]},{\"id\":\"a5c5746934670306\",\"type\":\"file\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"Log Data to CSV file\",\"filename\":\"filename\",\"filenameType\":\"msg\",\"appendNewline\":true,\"createDir\":true,\"overwriteFile\":\"false\",\"encoding\":\"none\",\"x\":940,\"y\":320,\"wires\":[[\"2518dc909d447655\"]]},{\"id\":\"d796d3aee8ea0343\",\"type\":\"OpcUa-Client\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"endpoint\":\"\",\"action\":\"read\",\"deadbandtype\":\"a\",\"deadbandvalue\":1,\"time\":10,\"timeUnit\":\"s\",\"certificate\":\"n\",\"localfile\":\"\",\"localkeyfile\":\"\",\"securitymode\":\"None\",\"securitypolicy\":\"None\",\"useTransport\":false,\"maxChunkCount\":1,\"maxMessageSize\":8192,\"receiveBufferSize\":8192,\"sendBufferSize\":8192,\"setstatusandtime\":false,\"keepsessionalive\":false,\"name\":\"\",\"x\":420,\"y\":320,\"wires\":[[\"4aff5b57cbb63b8f\"],",[493,6605],{},[493,6607],{},"]},{\"id\":\"23ebc0da4315ac46\",\"type\":\"inject\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"\",\"props\":",[493,6610,6611],{},"{\"p\":\"topic\",\"vt\":\"str\"}",",\"repeat\":\"5\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"ns=3;i=1004\",\"x\":220,\"y\":320,\"wires\":[[\"d796d3aee8ea0343\"]]},{\"id\":\"181ed86f9c11d1f7\",\"type\":\"catch\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"\",\"scope\":",[493,6614,6615],{},"\"a5c5746934670306\"",",\"uncaught\":false,\"x\":180,\"y\":420,\"wires\":[[\"b34d440897108110\"]]},{\"id\":\"b34d440897108110\",\"type\":\"debug\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"Errrors\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":630,\"y\":420,\"wires\":",[493,6618],{},"},{\"id\":\"575ed67714072973\",\"type\":\"function\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"Check Disk Space\",\"func\":\"try {\\n    \u002F\u002F Get disk usage information\\n    const stats = fs.statfsSync('.\u002F');\\n\\n    const totalSpace = stats.blocks * stats.bsize;\\n    const freeSpace = stats.bfree * stats.bsize;\\n    const usedSpace = totalSpace - freeSpace;\\n    const percentUsed = (usedSpace \u002F totalSpace) * 100;\\n\\n    msg.payload = {\\n        totalGB: (totalSpace \u002F (1024 ** 3)).toFixed(2),\\n        freeGB: (freeSpace \u002F (1024 ** 3)).toFixed(2),\\n        usedGB: (usedSpace \u002F (1024 ** 3)).toFixed(2),\\n        percentUsed: percentUsed.toFixed(2)\\n    };\\n\\n    \u002F\u002F Warning threshold\\n    if (percentUsed > 90) {\\n        msg.warning = ",[349,6621,6622],{},"Disk space critical: ${percentUsed.toFixed(1)}% used",";\\n    }\\n\\n    return msg;\\n\\n} catch (err) {\\n    msg.payload = { error: err.message };\\n    return msg;\\n}\",\"outputs\":1,\"timeout\":0,\"noerr\":0,\"initialize\":\"\",\"finalize\":\"\",\"libs\":",[493,6625,6626],{},"{\"var\":\"fs\",\"module\":\"fs\"}",",\"x\":430,\"y\":500,\"wires\":[[\"e719ae6fee22c812\"]]},{\"id\":\"d08353a9c90b0396\",\"type\":\"inject\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"\",\"props\":",[493,6629,6630],{},"{\"p\":\"payload\"},{\"p\":\"topic\",\"vt\":\"str\"}",",\"repeat\":\"1800\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"date\",\"x\":210,\"y\":500,\"wires\":[[\"575ed67714072973\"]]},{\"id\":\"e719ae6fee22c812\",\"type\":\"debug\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"Disk Full Warning !\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":670,\"y\":500,\"wires\":",[493,6633],{},"},{\"id\":\"2518dc909d447655\",\"type\":\"debug\",\"z\":\"FFF0000000000001\",\"g\":\"66776385db5794bc\",\"name\":\"Result\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":1110,\"y\":320,\"wires\":",[493,6636],{},"},{\"id\":\"7131c5523d86fe8b\",\"type\":\"global-config\",\"env\":",[493,6639],{},",\"modules\":{\"node-red-contrib-opcua\":\"0.2.342\"}}","\n{% endrenderFlow %}",[26,6643,1456],{"id":1455},[16,6645,6646],{},"You now have a production-ready PLC data logging system built on FlowFuse. It addresses the key reliability issues that typically cause downtime, connection drops, write failures, disk space limits, and daily file rotation, turning a simple flow into one that can run unattended for months.",[16,6648,6649],{},"The use of CSV ensures long-term data accessibility. Every analytics platform, database, and spreadsheet can read it, and it will remain usable decades from now, regardless of what tools or systems you adopt in the future.",[16,6651,6652],{},"Start small: connect one PLC, verify data quality, and deploy your first logging flow. Then gradually add error handling, storage monitoring, and redundancy as needed. Over time, this setup becomes a foundation for scalable, dependable industrial data collection.",[16,6654,6655],{},"FlowFuse makes this process straightforward by combining Node-RED’s flexibility with enterprise-grade management and monitoring. You can deploy updates remotely, manage devices across multiple sites, and standardize data collection, all from a single platform.",[16,6657,6658],{},"And while CSV is a reliable starting point, FlowFuse also integrates seamlessly with modern databases and historians like InfluxDB, TimescaleDB, and MySQL. Even better, FlowFuse Cloud includes a built-in PostgreSQL service and an AI Query Node that lets you explore your data conversationally, turning raw logs into actionable insights.",[16,6660,6661,6662,285],{},"For more on how FlowFuse connects PLCs across OPC UA, Siemens S7, EtherNet\u002FIP, and Modbus to collect and route industrial data, see the ",[105,6663,1475],{"href":1474},[328,6665,6666],{},[16,6667,6668,6669,6672],{},"You can ",[105,6670,6671],{"href":1934},"talk to our team",", they’ll walk you through a live demo showing how FlowFuse helps you connect, collect, transform, and visualize your industrial data reliably and intelligently.",[1477,6674,6675],{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":230,"searchDepth":231,"depth":231,"links":6677},[6678,6679,6685,6691,6692,6693],{"id":288,"depth":234,"text":289},{"id":5526,"depth":234,"text":5527,"children":6680},[6681,6682,6683,6684],{"id":5533,"depth":507,"text":5534},{"id":5560,"depth":507,"text":5561},{"id":5598,"depth":507,"text":4211},{"id":5604,"depth":507,"text":5605},{"id":5620,"depth":234,"text":5621,"children":6686},[6687,6688,6689,6690],{"id":5627,"depth":507,"text":5628},{"id":5648,"depth":507,"text":5649},{"id":5959,"depth":507,"text":5960},{"id":6006,"depth":507,"text":6007},{"id":6057,"depth":234,"text":6058},{"id":6555,"depth":234,"text":6556},{"id":1455,"depth":234,"text":1456},"2025-10-22","Learn how to reliably log PLC data to CSV files using FlowFuse, handling connection drops, file corruption, and timestamp drift.","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Flog-plc-data-to-csv.png",{"keywords":6698,"excerpt":6699},"PLC data logging, CSV file logging, Node-RED industrial automation, OPC UA data collection, FlowFuse, manufacturing data logging, SCADA data export, industrial IoT, Modbus logging, time-series data, edge device data collection, shop floor data collection",{"type":13,"value":6700},[6701],[16,6702,5487],{},"\u002Fblog\u002F2025\u002F10\u002Fhow-to-log-plc-data-csv-files",{"title":5481,"description":6695},{"loc":6703},"blog\u002F2025\u002F10\u002Fhow-to-log-plc-data-csv-files","Building a reliable, hands-off CSV logging setup with FlowFuse",[1518,263],"GY-EUo5WQBY0l6SRp6k7pVx7lgrgAVX37fUdYCr9yiU",{"id":6711,"title":6712,"authors":6713,"body":6714,"cta":3,"date":7281,"description":7282,"extension":248,"image":7283,"lastUpdated":1506,"meta":7284,"navigation":255,"path":7290,"seo":7291,"sitemap":7292,"stem":7293,"subtitle":7294,"tags":7295,"tldr":3,"video":3,"__hash__":7297},"blog\u002Fblog\u002F2025\u002F10\u002Fusing-ethernet-ip-with-flowfuse.md","EtherNet\u002FIP Integration with FlowFuse: Communicating with Allen-Bradley PLCs",[11],{"type":13,"value":6715,"toc":7262},[6716,6719,6722,6724,6727,6732,6746,6751,6765,6778,6783,6794,6798,6801,6810,6814,6817,6820,6826,6832,6836,6839,6842,6845,6849,6852,6874,6885,6889,6892,6959,6967,6974,6977,6981,6984,7011,7019,7022,7030,7035,7037,7046,7049,7052,7060,7063,7067,7070,7087,7095,7110,7113,7117,7120,7123,7138,7146,7160,7163,7168,7172,7175,7178,7204,7212,7220,7232,7235,7237,7240,7248,7252,7257],[16,6717,6718],{},"EtherNet\u002FIP is one of the most widely used industrial communication protocols for connecting PLCs, sensors, and controllers across manufacturing environments. If you're working with Allen-Bradley PLCs, whether it's ControlLogix, CompactLogix, or MicroLogix, you're using some of the most trusted automation hardware in the industry.",[16,6720,6721],{},"This guide will show you how to integrate Allen-Bradley PLCs with FlowFuse using EtherNet\u002FIP. While the focus is on Allen-Bradley, the same Node-RED nodes and techniques also work with other EtherNet\u002FIP-compatible PLCs, such as Omron and Automation Direct. You will learn both connected and unconnected messaging modes, so you can choose the approach that fits your setup. By the end of this guide, your PLCs will be communicating with FlowFuse (Node-RED with enterprise capabilities), enabling you to build powerful industrial automation workflows.",[26,6723,289],{"id":288},[16,6725,6726],{},"Before integrating your Allen-Bradley PLC with FlowFuse, ensure you have the following:",[16,6728,6729],{},[59,6730,6731],{},"PLC Configuration:",[53,6733,6734,6737,6740,6743],{},[56,6735,6736],{},"Your Allen-Bradley PLC (ControlLogix, CompactLogix, or MicroLogix) should be properly configured and operational.",[56,6738,6739],{},"Ensure that the appropriate ladder logic program is written according to your requirements and successfully downloaded to the PLC.",[56,6741,6742],{},"Verify that the controller tags or data structures you want to access are properly defined.",[56,6744,6745],{},"Note the PLC's IP address and slot number (typically slot 0 for the processor).",[16,6747,6748],{},[59,6749,6750],{},"Node-RED:",[53,6752,6753,6756],{},[56,6754,6755],{},"Install Node-RED on the device that will communicate with the Allen-Bradley PLC. You cannot install Node-RED directly on the PLC, as PLCs are controllers, not computers. You can use devices like the Raspberry Pi, Revolution Pi, or industrial PCs to connect and transfer data across systems.",[56,6757,6758,6759,6764],{},"Use the ",[105,6760,6763],{"href":6761,"rel":6762},"https:\u002F\u002Fflowfuse.com\u002Fplatform\u002Fdevice-agent\u002F",[1240],"FlowFuse Device Agent"," to install Node-RED on your edge device.",[328,6766,6767],{},[16,6768,6769,6772,6773,6777],{},[59,6770,6771],{},"Why FlowFuse Device Agent?"," FlowFuse provides Node-RED with enterprise capabilities like remote management, team collaboration, device management, and DevOps pipelines, essential features for scaling industrial automation across your organization. These capabilities help streamline operations and ensure reliability in complex manufacturing environments. ",[105,6774,6776],{"href":5441,"rel":6775},[1240],"Sign up for free"," to get started.",[16,6779,6780],{},[59,6781,6782],{},"Network Setup:",[53,6784,6785,6788,6791],{},[56,6786,6787],{},"Verify that the device running Node-RED is on the same network as the PLC and can successfully ping the PLC's IP address.",[56,6789,6790],{},"Ensure the PLC is properly connected to the network via Ethernet with a static IP address configured.",[56,6792,6793],{},"Ensure that firewalls do not block EtherNet\u002FIP communication (typically port 44818 for both TCP and UDP).",[26,6795,6797],{"id":6796},"understanding-ethernetip-communication-modes","Understanding EtherNet\u002FIP Communication Modes",[16,6799,6800],{},"EtherNet\u002FIP is an industrial network protocol widely used to communicate with Allen-Bradley and other PLCs over Ethernet. It allows devices to exchange data efficiently and reliably, making it a common choice for industrial automation systems.",[16,6802,6803,6804,811,6806,6809],{},"EtherNet\u002FIP supports two primary communication modes: ",[59,6805,859],{},[59,6807,6808],{},"unconnected"," messaging. Your choice depends on how frequently you need to communicate with the PLC, the number of available connection resources, and, most importantly, what your PLC actually supports. Not all PLCs support both modes. For example, Allen-Bradley Micro800 series PLCs only support connected messaging, while ControlLogix and CompactLogix typically support both.",[1224,6811,6813],{"id":6812},"connected-messaging","Connected Messaging",[16,6815,6816],{},"Connected messaging establishes a persistent session between Node-RED and the PLC using the Forward Open protocol. Once connected, data flows continuously with minimal overhead, making it ideal for real-time monitoring and high-frequency updates. The advantage is speed, after the initial handshake, communication is fast and efficient. The tradeoff is that each session consumes one of the PLC's limited connection slots, typically ranging from 8 to 32 depending on the model.",[16,6818,6819],{},"Connected messaging itself can operate in two ways:",[16,6821,6822,6825],{},[59,6823,6824],{},"Without Routing (Direct Connection):","\nUsed for PLCs that connect directly via Ethernet without backplane routing, such as the Allen-Bradley Micro800\u002F850\u002F870 series. Only the IP address is needed, no slot number or routing path is required.",[16,6827,6828,6831],{},[59,6829,6830],{},"With Routing:","\nUsed for chassis-based PLCs like ControlLogix and CompactLogix, where the processor sits in a backplane slot. In this case, the slot number must be specified, as it automatically creates a routing path through the backplane to reach the processor.",[1224,6833,6835],{"id":6834},"unconnected-messaging","Unconnected Messaging",[16,6837,6838],{},"Unconnected messaging sends individual requests without maintaining a persistent connection. Each transaction is standalone, request, response, done.",[16,6840,6841],{},"This approach doesn't consume connection slots, making it ideal when resources are limited or when multiple systems need occasional PLC access. The downside is higher overhead per message, resulting in slower performance compared to connected mode.",[16,6843,6844],{},"In practice, use connected mode for frequent polling and unconnected mode for occasional reads or writes, but always check your PLC's documentation to confirm which modes are supported.",[26,6846,6848],{"id":6847},"installing-the-ethernetip-node","Installing the EtherNet\u002FIP Node",[16,6850,6851],{},"To communicate with Allen-Bradley PLCs from FlowFuse, use the popular node-red-contrib-cip-ethernet-ip node, which supports both connected and unconnected messaging modes.",[472,6853,6854,6857,6860,6863,6868,6871],{},[56,6855,6856],{},"Open your FlowFuse Instance Node-RED editor in a web browser.",[56,6858,6859],{},"Click the main menu (three horizontal lines) in the top-right corner.",[56,6861,6862],{},"Select \"Manage Palette\" from the menu.",[56,6864,6865,6866,285],{},"Switch to the \"Install\" tab and search for ",[349,6867,4148],{},[56,6869,6870],{},"Click \"Install\" next to the node name.",[56,6872,6873],{},"Wait for the installation to complete.",[16,6875,6876,6877,6880,6881,6884],{},"Once installed, you'll find the EtherNet\u002FIP nodes in your palette under the \"plc\" category. The main nodes are ",[349,6878,6879],{},"ethernet-ip in"," for reading data and ",[349,6882,6883],{},"ethernet-ip out"," for writing data to the PLC.",[26,6886,6888],{"id":6887},"configuring-the-ethernetip-node","Configuring the EtherNet\u002FIP Node",[16,6890,6891],{},"Now that you have installed the EtherNet\u002FIP node, it is time to configure the connection to your Allen-Bradley PLC.",[472,6893,6894,6897,6900,6907,6932,6942],{},[56,6895,6896],{},"Drag any EtherNet\u002FIP node onto the canvas.",[56,6898,6899],{},"Double-click the node to open its configuration panel.",[56,6901,6902,6903,6906],{},"Click the \"+\" icon next to the ",[59,6904,6905],{},"\"PLC\""," dropdown to add a new PLC configuration.",[56,6908,6909,6910],{},"Enter the basic connection details:",[53,6911,6912,6919,6925],{},[56,6913,6914,6915,6918],{},"Give your connection a descriptive name, such as ",[59,6916,6917],{},"\"Line 1 PLC\"",", for easy identification.",[56,6920,6921,6922,285],{},"Enter your PLC’s ",[59,6923,6924],{},"IP address",[56,6926,6927,6928,6931],{},"Specify the ",[59,6929,6930],{},"slot number"," where your processor is located.",[56,6933,6934,6935],{},"Configure the communication parameters:",[53,6936,6937],{},[56,6938,6939,6941],{},[59,6940,1002],{}," controls how often the node communicates with the PLC (for example, 500 ms means it updates twice per second).",[56,6943,6944,6945],{},"Select the communication mode:",[53,6946,6947,6953],{},[56,6948,6949,6952],{},[59,6950,6951],{},"Standard (Unconnected)",": This is the default option supported by most PLCs.",[56,6954,6955,6958],{},[59,6956,6957],{},"Connected (With Routing)",": Use this option if you want to enable connected messaging with routing.",[16,6960,6961,6965],{},[650,6962],{"alt":6963,"dataZoomable":230,"src":6964},"EtherNet\u002FIP Node Configuration","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Feth-ip-config.png",[1529,6966,6963],{},[16,6968,6969,6970,6973],{},"This node does not currently support connected messaging (without routing). I have developed node, ",[349,6971,6972],{},"@sumit_shinde_84\u002Fnode-red-contrib-cip-ethernet-ip-enhanced",", which supports connected messaging (without routing) but is still under development.",[16,6975,6976],{},"If you need connected messaging without routing, you can use that node. To enable connected messaging without routing, select Connected (no routing) from the communication mode dropdown in the configuration dialog.",[1224,6978,6980],{"id":6979},"adding-tags-to-read-or-write","Adding Tags to Read or Write",[16,6982,6983],{},"After configuring the endpoint, you need to specify which tags you want to read from or write to the PLC.",[472,6985,6986,6989,6992,7008],{},[56,6987,6988],{},"In the same configuration window, switch to the \"Tags\" tab.",[56,6990,6991],{},"Click the \"+Add\" button in the top-right corner to add a new tag.",[56,6993,6994,6995],{},"Enter the tag details:",[53,6996,6997,7003],{},[56,6998,6999,7002],{},[59,7000,7001],{},"Name",": Enter the exact tag name as it appears in your PLC program (e.g., \"Motor1Speed\" or \"Program:MainProgram.Motor1Speed\")",[56,7004,7005,7007],{},[59,7006,4570],{},": Select the data type from the dropdown (e.g., BOOL, INT, DINT, REAL, etc.)",[56,7009,7010],{},"Repeat this process for each tag you want to monitor or control. You can add multiple tags that will all use the same PLC connection you configured earlier.",[16,7012,7013,7017],{},[650,7014],{"alt":7015,"dataZoomable":230,"src":7016},"Adding tags to read and write","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fadding-tags.gif",[1529,7018,7015],{},[16,7020,7021],{},"If your tag belongs to a different scope, click the “+ Add” button at the top to create a new scope. Then, within that scope, add the tags in the same manner.",[472,7023,7024,7027],{"start":518},[56,7025,7026],{},"Once you've added all your tags, click \"Add\" to save the configuration, then \"Done\".",[56,7028,7029],{},"Finally, deploy the flow by clicking the \"Deploy\" button in the top-right corner.",[16,7031,7032,7034],{},[59,7033,434],{}," Tag names must match exactly as they appear in your PLC program, they are case-sensitive. Make sure to select the correct data type for each tag to ensure proper communication.",[26,7036,2896],{"id":2895},[16,7038,7039,7040,7045],{},"Before we start, I'd like to show you what I've prepared, a flow where I'm sending commands to the PLC to control the stack light. To interact with it, I've built a nice dashboard using ",[105,7041,7044],{"href":7042,"rel":7043},"https:\u002F\u002Fdashboard.flowfuse.com\u002F",[1240],"FlowFuse Dashboard",". Here's a quick demonstration:",[950,7047],{"videoid":7048,"params":2732,"style":2733,"title":2734},"6X9HXJLKPyo",[16,7050,7051],{},"That’s the program I have downloaded to the PLC",[16,7053,7054,7058],{},[650,7055],{"alt":7056,"dataZoomable":230,"src":7057},"Program downloaded to the PLC","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fplc-program.png",[1529,7059,7056],{},[16,7061,7062],{},"Now let’s learn how to build a flow that can both read and write data to your PLC.",[1224,7064,7066],{"id":7065},"writing-data-to-your-plc","Writing Data to Your PLC",[16,7068,7069],{},"Writing to a PLC is where things get exciting, this is where you move from monitoring to actually controlling your equipment. Maybe you want to start a motor, adjust a setpoint, or trigger a sequence. Whatever your goal, the process is straightforward.",[472,7071,7072,7078,7081,7084],{},[56,7073,878,7074,3231],{},[59,7075,7076],{},[349,7077,6883],{},[56,7079,7080],{},"Double-click the node to open its configuration.",[56,7082,7083],{},"Select the PLC configuration you created earlier from the dropdown.",[56,7085,7086],{},"Select the scope under which you added the tag, choose the tag that you want to write to.",[16,7088,7089,7093],{},[650,7090],{"alt":7091,"dataZoomable":230,"src":7092},"Configuring the EtherNet\u002FIP out node to write data to a PLC tag","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Feth-out-node.png",[1529,7094,7091],{},[472,7096,7097,7100,7107],{"start":518},[56,7098,7099],{},"Click \"Done\".",[56,7101,3048,7102,7106],{},[59,7103,7104],{},[349,7105,881],{}," node or any other input node to send data.",[56,7108,7109],{},"Deploy the flow and click inject button to test it.",[16,7111,7112],{},"The node expects the incoming message payload to contain the value you want to write to the tag. Ensure that the value type matches the data type you configured when adding the tag and what the PLC expects.",[1224,7114,7116],{"id":7115},"reading-single-tag-from-your-plc","Reading Single Tag from Your PLC",[16,7118,7119],{},"Reading data from your PLC is the foundation of any monitoring or control system. Whether you're tracking production counts, monitoring temperatures, or checking machine status, you'll start here.",[16,7121,7122],{},"Here's how to set it up:",[472,7124,7125,7131,7133,7135],{},[56,7126,878,7127,3231],{},[59,7128,7129],{},[349,7130,6879],{},[56,7132,7080],{},[56,7134,7083],{},[56,7136,7137],{},"Select the scope under which you added the tag, select the mode to \"Single Tag\" and choose the tag that you want to read.",[16,7139,7140,7144],{},[650,7141],{"alt":7142,"dataZoomable":230,"src":7143},"Configuring the EtherNet\u002FIP in node to read a single tag from the PLC","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fread-plc-tag.png",[1529,7145,7142],{},[472,7147,7148,7150,7158],{"start":518},[56,7149,7099],{},[56,7151,7152,7153,7157],{},"Connect a ",[59,7154,7155],{},[349,7156,935],{}," node to view the data.",[56,7159,3711],{},[16,7161,7162],{},"The node will automatically read data based on your configured cycle time and output it.",[16,7164,7165],{},[1529,7166,7167],{},"Note: Reading single tags individually isn't recommended for production use as it creates unnecessary network overhead. Consider using \"All tags\" mode or structuring your PLC with array data types to read multiple values efficiently in one request.",[1224,7169,7171],{"id":7170},"reading-multiple-tags-from-your-plc","Reading Multiple Tags from Your PLC",[16,7173,7174],{},"Sometimes you need the full picture, not just one data point, but everything that matters for your process. Reading multiple tags at once gives you a complete snapshot of your system in a single message.",[16,7176,7177],{},"Let me show you how:",[472,7179,7180,7186,7188,7190],{},[56,7181,878,7182,3231],{},[59,7183,7184],{},[349,7185,6879],{},[56,7187,7080],{},[56,7189,7083],{},[56,7191,688,7192,7195,7196,7199,7200,7203],{},[59,7193,7194],{},"Mode"," field, select ",[59,7197,7198],{},"\"All tags\""," to read all configured tags together in a single message, or select ",[59,7201,7202],{},"\"All tags (one per msg)\""," if you want each tag value sent as a separate message.",[16,7205,7206,7210],{},[650,7207],{"alt":7208,"dataZoomable":230,"src":7209},"Reading all tags with each tag sent as a separate message","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fall-tags-one-msg-per-tag.png",[1529,7211,7208],{},[16,7213,7214,7218],{},[650,7215],{"alt":7216,"dataZoomable":230,"src":7217},"Reading all tags together in a single message object","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fall-tags-single-obj.png",[1529,7219,7216],{},[472,7221,7222,7224,7230],{"start":518},[56,7223,7099],{},[56,7225,7152,7226,7157],{},[59,7227,7228],{},[349,7229,935],{},[56,7231,3711],{},[16,7233,7234],{},"The node will automatically read all configured tags based on your cycle time, giving you full visibility into your PLC data.",[26,7236,4931],{"id":4930},[16,7238,7239],{},"Now that you've learned how to read and write data with your Allen-Bradley PLC, you can build interactive dashboards to monitor and control your industrial processes. FlowFuse Dashboard makes it easy to create professional interfaces with buttons, gauges, charts, and controls, all without writing complex code.",[16,7241,7242,7243,7247],{},"Check out our ",[105,7244,7246],{"href":7245},"\u002Fblog\u002F2024\u002F03\u002Fdashboard-getting-started\u002F","Getting Started with Dashboard guide"," to learn how to build your first dashboard.",[1224,7249,7251],{"id":7250},"beyond-allen-bradley","Beyond Allen-Bradley",[16,7253,7254,7255,285],{},"FlowFuse isn't limited to EtherNet\u002FIP. Connect Siemens PLCs via S7, use OPC UA for vendor-neutral communication, integrate Modbus devices, or connect IoT sensors with MQTT. Mix protocols as needed, your factory floor probably isn't single-vendor anyway. For a full view of every supported PLC brand and protocol, see the ",[105,7256,1475],{"href":1474},[16,7258,7259,7261],{},[105,7260,1935],{"href":1934}," to see how FlowFuse connects your entire operation.",{"title":230,"searchDepth":231,"depth":231,"links":7263},[7264,7265,7269,7270,7273,7278],{"id":288,"depth":234,"text":289},{"id":6796,"depth":234,"text":6797,"children":7266},[7267,7268],{"id":6812,"depth":507,"text":6813},{"id":6834,"depth":507,"text":6835},{"id":6847,"depth":234,"text":6848},{"id":6887,"depth":234,"text":6888,"children":7271},[7272],{"id":6979,"depth":507,"text":6980},{"id":2895,"depth":234,"text":2896,"children":7274},[7275,7276,7277],{"id":7065,"depth":507,"text":7066},{"id":7115,"depth":507,"text":7116},{"id":7170,"depth":507,"text":7171},{"id":4930,"depth":234,"text":4931,"children":7279},[7280],{"id":7250,"depth":507,"text":7251},"2025-10-10","Learn how to integrate Allen-Bradley PLCs with FlowFuse using EtherNet\u002FIP. This guide covers connected and unconnected messaging, reading and writing tags, and building industrial automation workflows in Node-RED.","\u002Fblog\u002F2025\u002F10\u002Fimages\u002Fallen-bradly-plc.png",{"keywords":7285,"excerpt":7286},"EtherNet\u002FIP, Allen-Bradley PLC, FlowFuse, Node-RED, industrial automation, connected messaging, PLC integration",{"type":13,"value":7287},[7288],[16,7289,6718],{},"\u002Fblog\u002F2025\u002F10\u002Fusing-ethernet-ip-with-flowfuse",{"title":6712,"description":7282},{"loc":7290},"blog\u002F2025\u002F10\u002Fusing-ethernet-ip-with-flowfuse","A guide to connected and unconnected EtherNet\u002FIP communication with FlowFuse",[1518,7296,262,263],"node-red","Tls9rf54vSdWRttZ1o0U98x_fSTsda8vKcJVMfRL1Rw",{"id":7299,"title":7300,"authors":7301,"body":7302,"cta":3,"date":8173,"description":8174,"extension":248,"image":8175,"lastUpdated":3,"meta":8176,"navigation":255,"path":8182,"seo":8183,"sitemap":8184,"stem":8185,"subtitle":8186,"tags":8187,"tldr":8189,"video":3,"__hash__":8190},"blog\u002Fblog\u002F2025\u002F07\u002Freading-and-writing-plc-data-using-opc-ua.md","OPC UA Tutorial: Connect and Exchange Data with Industrial Equipment",[11],{"type":13,"value":7303,"toc":8147},[7304,7307,7312,7315,7326,7352,7356,7359,7363,7366,7370,7373,7377,7380,7384,7387,7391,7394,7396,7399,7402,7406,7409,7417,7420,7423,7426,7430,7433,7437,7461,7474,7478,7481,7508,7524,7533,7541,7544,7548,7551,7587,7590,7598,7612,7616,7619,7623,7626,7703,7710,7718,7721,7728,7752,7756,7759,7768,7778,7824,7827,7850,7854,7857,7861,7864,7954,7960,7983,7987,7990,8072,8075,8101,8105,8108,8115,8118,8132,8138,8141],[16,7305,7306],{},"If you’ve ever tried to connect industrial equipment from different vendors, you know how frustrating it can be, a mess of incompatible protocols, proprietary software, and confusing drivers. Your Siemens PLC speaks one language, your Allen-Bradley controller another, and that Modbus sensor? Yet another protocol entirely.",[16,7308,7309],{},[59,7310,7311],{},"OPC UA changes that.",[16,7313,7314],{},"OPC UA (Open Platform Communications Unified Architecture) is the industry-standard protocol that eliminates this chaos. Also known as OPC Unified Architecture or IEC 62541, it provides a universal language for secure communication between PLCs, SCADA systems, HMIs, and enterprise applications ,regardless of the manufacturer.",[16,7316,7317,7318,7321,7322,811,7324,4602],{},"This hands-on guide walks you through building your first ",[59,7319,7320],{},"OPC UA integration"," using ",[59,7323,1886],{},[59,7325,284],{},[53,7327,7328,7334,7340,7346],{},[56,7329,7330,7333],{},[59,7331,7332],{},"Connect"," to any OPC UA server, Kepware, MatrikonOPC, or built-in PLC servers",[56,7335,7336,7339],{},[59,7337,7338],{},"Browse"," available tags and discover Node IDs from your equipment",[56,7341,7342,7345],{},[59,7343,7344],{},"Read"," real-time values from PLCs, sensors, and industrial devices",[56,7347,7348,7351],{},[59,7349,7350],{},"Write"," control signals and setpoints back to your systems",[26,7353,7355],{"id":7354},"why-opc-ua","Why OPC UA?",[16,7357,7358],{},"If you have worked with industrial equipment, you know the pain. Every PLC vendor uses a different protocol. Your Siemens S7-1500 requires TIA Portal and PROFINET drivers. The Allen-Bradley ControlLogix needs RSLinx and EtherNet\u002FIP. A Modbus temperature sensor needs yet another tool. Before long, you are juggling a dozen different software packages, each with its own licensing, training, and maintenance overhead.",[1224,7360,7362],{"id":7361},"breaking-the-cycle","Breaking the Cycle",[16,7364,7365],{},"OPC UA eliminates this fragmentation. Instead of relying on vendor-specific protocols, it provides a universal language for all your equipment. Here is why it is becoming the industry standard:",[1224,7367,7369],{"id":7368},"universal-connectivity","Universal Connectivity",[16,7371,7372],{},"Connect to any modern PLC using a single protocol. Leading manufacturers like Siemens, Rockwell, Schneider, and ABB now embed OPC UA servers directly into their controllers. One client, all your equipment.",[1224,7374,7376],{"id":7375},"information-not-just-data","Information, Not Just Data",[16,7378,7379],{},"Reading a temperature value from OPC UA does not just give you \"42.5\", it gives the full context: 42.5 °C, measured at 14:32:15.625 with \"Good\" quality, from \"Tank_01\u002FTemperature\", and includes alarm limits (10 °C \u002F 80 °C). This context reduces guesswork and helps prevent costly mistakes.",[1224,7381,7383],{"id":7382},"security-built-for-industry","Security Built for Industry",[16,7385,7386],{},"While protocols like Modbus transmit everything in plain text, OPC UA uses enterprise-grade security. It supports X.509 certificates, 256-bit encryption, and robust user authentication to safeguard critical infrastructure from cyber threats.",[1224,7388,7390],{"id":7389},"future-proof-investment","Future-Proof Investment",[16,7392,7393],{},"OPC UA is the foundation of Industry 4.0 initiatives around the world. It is not just another protocol, it is the one major vendors are standardizing on. Choosing OPC UA today ensures long-term compatibility and ROI.",[26,7395,2896],{"id":2895},[16,7397,7398],{},"Now that you understand why OPC UA is widely adopted, let’s explore how to implement it using FlowFuse Node-RED.",[16,7400,7401],{},"This next section walks you through exactly what you need to get started with a working setup, whether for prototyping or production.",[1224,7403,7405],{"id":7404},"what-youll-need","What You’ll Need",[16,7407,7408],{},"Before diving into the flow-building process, make sure you have the following:",[53,7410,7411,7414],{},[56,7412,7413],{},"An OPC UA server (like Kepware, MatrikonOPC, or built into your PLC)",[56,7415,7416],{},"A FlowFuse Node-RED instance running on your edge device.",[16,7418,7419],{},"For production OPC UA deployments, we recommend using FlowFuse. When connecting to industrial systems, you need more than just Node-RED, you need team collaboration so multiple engineers can work on flows safely, audit logs for compliance tracking, high availability to prevent downtime, and remote device management for edge deployments.",[16,7421,7422],{},"FlowFuse provides these enterprise features plus automatic backups, one-click rollbacks, environment variables for different sites, and DevOps pipelines for testing changes before they reach production.",[16,7424,7425],{},"[Get started →]({% include \"sign-up-url.njk\" %})",[1224,7427,7429],{"id":7428},"installing-opc-ua-support-in-flowfuse","Installing OPC UA Support in FlowFuse",[16,7431,7432],{},"To work with OPC UA in FlowFuse Node-RED, you will first need to install the required nodes.",[3431,7434,7436],{"id":7435},"install-the-opc-ua-node-package","Install the OPC UA Node Package",[472,7438,7439,7444,7449,7457],{},[56,7440,2544,7441,285],{},[59,7442,7443],{},"FlowFuse Node-RED editor",[56,7445,7446,7447,285],{},"Click the menu in the top-right and choose ",[59,7448,2377],{},[56,7450,7451,7452,7454,7455,285],{},"Navigate to the ",[59,7453,625],{}," tab and search for ",[349,7456,2387],{},[56,7458,635,7459,285],{},[59,7460,625],{},[16,7462,7463,7464,1447,7467,1450,7470,7473],{},"Once installed, you will find new nodes for OPC UA communication in your palette, including ",[59,7465,7466],{},"Client",[59,7468,7469],{},"Item",[59,7471,7472],{},"Browser"," and other OPC UA nodes.",[1224,7475,7477],{"id":7476},"connecting-to-your-opc-ua-server","Connecting to Your OPC UA Server",[16,7479,7480],{},"To begin accessing industrial data, create a client connection using the OPC UA Client node.",[472,7482,7483,7487,7490,7496,7502],{},[56,7484,878,7485,3231],{},[59,7486,4228],{},[56,7488,7489],{},"Double-click to configure it.",[56,7491,7492,7493,7495],{},"Click the ",[59,7494,684],{}," icon to create a new endpoint configuration.",[56,7497,7498,7499],{},"Enter your OPC UA server address, for example: ",[349,7500,7501],{},"opc.tcp:\u002F\u002F192.168.0.10:4840",[56,7503,7504,7505,7507],{},"Set the security mode to ",[59,7506,2156],{}," (you can add security later).",[328,7509,7510],{},[16,7511,7512,7515,7516,7519,7520,7523],{},[59,7513,7514],{},"Security Note:"," This tutorial uses ",[59,7517,7518],{},"\"None\""," for the security setting to keep things simple.\nIn production environments, always use appropriate security, typically ",[59,7521,7522],{},"\"Sign & Encrypt\""," with certificates.",[472,7525,7526],{"start":524},[56,7527,635,7528,7530,7531,285],{},[59,7529,842],{},", then ",[59,7532,848],{},[16,7534,7535,7539],{},[650,7536],{"alt":7537,"dataZoomable":230,"src":7538},"OPC UA endpoint configuration","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fopcua-endpoint-config.png",[1529,7540,7537],{},[16,7542,7543],{},"With the connection now defined, you’re ready to explore what tags are available.",[1224,7545,7547],{"id":7546},"browsing-tags-optional","Browsing Tags (Optional)",[16,7549,7550],{},"If you do not already know the Node IDs of the tags you want to access, use the OPC UA Browser node to explore the tag structure.",[472,7552,7553,7562,7568,7581,7584],{},[56,7554,878,7555,1447,7557,1450,7560,3231],{},[59,7556,2495],{},[59,7558,7559],{},"OPC UA Browser",[59,7561,2505],{},[56,7563,7564,7565,7567],{},"Connect the output of the Inject node to the input of the ",[59,7566,7472],{}," node, then connect the Browser's output to the Debug node.",[56,7569,688,7570,7572,7573,7576,7577,7580],{},[59,7571,7472],{}," node, set the topic to ",[349,7574,7575],{},"ns=0;i=85"," (the root ",[1529,7578,7579],{},"Objects"," folder).",[56,7582,7583],{},"Configure the Inject node to send a timestamp.",[56,7585,7586],{},"Deploy the flow and click the Inject node.",[16,7588,7589],{},"Tag information will be printed to the debug sidebar. You can now identify the exact Node IDs to use in your reads or writes.",[16,7591,7592,7596],{},[650,7593],{"alt":7594,"dataZoomable":230,"src":7595},"OPC UA Browser node","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fopcua-browser.png",[1529,7597,7594],{},[16,7599,6586,7600,6641],{},[493,7601,7602,7603,7605,7606,7608,7609,7611],{},"{\"id\":\"c3a8303048e6588f\",\"type\":\"OpcUa-Browser\",\"z\":\"f66e9c91c269e7fb\",\"endpoint\":\"c0f8c79fc00845c8\",\"item\":\"\",\"datatype\":\"\",\"topic\":\"ns=0;i=85\",\"items\":",[493,7604],{},",\"name\":\"\",\"x\":510,\"y\":300,\"wires\":[[\"3428199852f9fcdc\"]]},{\"id\":\"1549f797c58ba667\",\"type\":\"inject\",\"z\":\"f66e9c91c269e7fb\",\"name\":\"\",\"props\":",[493,7607,6630],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"date\",\"x\":280,\"y\":300,\"wires\":[[\"c3a8303048e6588f\"]]},{\"id\":\"3428199852f9fcdc\",\"type\":\"debug\",\"z\":\"f66e9c91c269e7fb\",\"name\":\"debug 1\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"false\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":740,\"y\":300,\"wires\":",[493,7610],{},"},{\"id\":\"c0f8c79fc00845c8\",\"type\":\"OpcUa-Endpoint\",\"endpoint\":\"\",\"secpol\":\"None\",\"secmode\":\"None\",\"none\":true,\"login\":false,\"usercert\":false,\"usercertificate\":\"\",\"userprivatekey\":\"\"}",[1224,7613,7615],{"id":7614},"reading-tag-values","Reading Tag Values",[16,7617,7618],{},"Once you know the Node IDs, you can start reading data from your industrial equipment through the OPC UA server.",[3431,7620,7622],{"id":7621},"reading-a-single-tag","Reading a Single Tag",[16,7624,7625],{},"Here’s how to read a single value in real time:",[472,7627,7628,7633,7665,7673,7688,7691],{},[56,7629,878,7630,7632],{},[59,7631,2495],{}," node onto the canvas (this will trigger the read operation).",[56,7634,4859,7635,7638,7639,7659,7661],{},[59,7636,7637],{},"OPC UA Item"," node and configure:",[53,7640,7641,7650],{},[56,7642,7643,7646,7647,2445],{},[59,7644,7645],{},"Node ID",": Enter the tag’s identifier (e.g., ",[349,7648,7649],{},"ns=3;i=1003",[56,7651,7652,7655,7656,2445],{},[59,7653,7654],{},"Data Type",": Select the appropriate type (e.g., ",[349,7657,7658],{},"Boolean",[5136,7660],{},[650,7662],{"alt":7663,"dataZoomable":230,"src":7664},"OPC UA Item node configuration","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fopcua-item-node.png",[56,7666,7667,7668,7670,7671,3116],{},"Connect the output of the ",[59,7669,2495],{}," node to the input of the ",[59,7672,7469],{},[56,7674,4859,7675,7677,7678,989,7680,285,7682,7684],{},[59,7676,4228],{}," node and set its ",[59,7679,2525],{},[349,7681,2614],{},[5136,7683],{},[650,7685],{"alt":7686,"dataZoomable":230,"src":7687},"OPC UA Client node configured for reading","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fopcua-client-read-node.png",[56,7689,7690],{},"Select the endpoint configuration you created earlier.",[56,7692,7667,7693,7670,7695,7697,7698,7700,7701,3116],{},[59,7694,7469],{},[59,7696,7466],{}," node, then connect the ",[59,7699,7466],{}," node's top output to a ",[59,7702,2505],{},[328,7704,7705],{},[16,7706,808,7707,7709],{},[59,7708,4228],{}," node has three outputs: the top carries the data payload, the middle indicates connection status, and the bottom provides raw responses for debugging.",[472,7711,7712],{"start":530},[56,7713,7714,7715,7717],{},"Deploy the flow and click the ",[59,7716,2495],{}," button to trigger the read.",[16,7719,7720],{},"You should see the tag value appear in the debug panel. This confirms that communication is working correctly.",[16,7722,7723,7724,7727],{},"You can also pass the Node ID dynamically using ",[349,7725,7726],{},"msg.topic"," from the Inject node if you prefer not to use an Item node.",[16,7729,6586,7730,6641],{},[493,7731,7732,7733,3269,7736,7739,7740,7742,7743,7745,7746,7748,7749,7751],{},"{\"id\":\"d128582dda7adbed\",\"type\":\"OpcUa-Client\",\"z\":\"ead97ed756a13a15\",\"endpoint\":\"a4df18253e5a79a0\",\"action\":\"read\",\"deadbandtype\":\"a\",\"deadbandvalue\":1,\"time\":10,\"timeUnit\":\"s\",\"certificate\":\"n\",\"localfile\":\"\",\"localkeyfile\":\"\",\"securitymode\":\"None\",\"securitypolicy\":\"None\",\"useTransport\":false,\"maxChunkCount\":1,\"maxMessageSize\":8192,\"receiveBufferSize\":8192,\"sendBufferSize\":8192,\"setstatusandtime\":false,\"keepsessionalive\":false,\"name\":\"\",\"x\":580,\"y\":240,\"wires\":[[\"3fc16bf912f16169\"],",[493,7734,7735],{},"\"17724a6889ec7378\"",[493,7737,7738],{},"\"c6b0f16ef7371699\"","]},{\"id\":\"3fc16bf912f16169\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Tag Value\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":740,\"y\":200,\"wires\":",[493,7741],{},"},{\"id\":\"2691196551812a21\",\"type\":\"OpcUa-Item\",\"z\":\"ead97ed756a13a15\",\"item\":\"ns=3;i=1001\",\"datatype\":\"Boolean\",\"value\":\"\",\"name\":\"OPC UA Item Node\",\"x\":370,\"y\":240,\"wires\":[[\"d128582dda7adbed\"]]},{\"id\":\"96d17841a7f13ac4\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Read tag\",\"props\":",[493,7744,6630],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"date\",\"x\":200,\"y\":200,\"wires\":[[\"2691196551812a21\"]]},{\"id\":\"17724a6889ec7378\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Errors\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":730,\"y\":240,\"wires\":",[493,7747],{},"},{\"id\":\"c6b0f16ef7371699\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Raw Respons\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":760,\"y\":280,\"wires\":",[493,7750],{},"},{\"id\":\"a4df18253e5a79a0\",\"type\":\"OpcUa-Endpoint\",\"endpoint\":\"opc.tcp:\u002F\u002F192.168.0.10:4840\",\"secpol\":\"None\",\"secmode\":\"None\",\"none\":true,\"login\":false,\"usercert\":false,\"usercertificate\":\"\",\"userprivatekey\":\"\"}",[3431,7753,7755],{"id":7754},"reading-multiple-tags","Reading Multiple Tags",[16,7757,7758],{},"Batch reading improves performance when you need multiple data points from your equipment",[472,7760,7761],{},[56,7762,878,7763,7677,7765,7767],{},[59,7764,4228],{},[59,7766,2525],{}," to \"READ MULTIPLE\".",[16,7769,7770,7774,7776],{},[650,7771],{"alt":7772,"dataZoomable":230,"src":7773},"Screenshot showing OPC UA Client node with \"READ MULTIPLE\" action selected","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fread-multiple.png",[5136,7775],{},[1529,7777,7772],{},[472,7779,7780,7783,7788,7793,7796,7799,7806,7808,7811,7818],{"start":234},[56,7781,7782],{},"Select the endpoint configuration.",[56,7784,4859,7785,7787],{},[59,7786,7637],{}," node for each tag you want to read.",[56,7789,4859,7790,7792],{},[59,7791,2495],{}," node for each Item node to trigger it.",[56,7794,7795],{},"Connect each Inject node to its corresponding Item node.",[56,7797,7798],{},"Wire all Item nodes into the OPC UA Client node.",[56,7800,4278,7801,7803,7804,3116],{},[59,7802,2505],{}," node to the top output of the ",[59,7805,7466],{},[56,7807,3711],{},[56,7809,7810],{},"Click each Inject node once, the client node will store the tag definitions.",[56,7812,7813,7814,7817],{},"Send a message with ",[349,7815,7816],{},"msg.topic = \"readmultiple\""," to trigger the actual read.",[56,7819,7820,7821,285],{},"To clear stored items, send ",[349,7822,7823],{},"msg.topic = \"clearitems\"",[16,7825,7826],{},"You now have a flexible setup for reading multiple values from your PLC on demand.",[16,7828,6586,7829,6641],{},[493,7830,7831,7832,3269,7835,7838,7839,7841,7842,7844,7845,7847,7848,5793],{},"{\"id\":\"6f5e2b1cbce15025\",\"type\":\"OpcUa-Client\",\"z\":\"ead97ed756a13a15\",\"endpoint\":\"\",\"action\":\"readmultiple\",\"deadbandtype\":\"a\",\"deadbandvalue\":1,\"time\":10,\"timeUnit\":\"s\",\"certificate\":\"n\",\"localfile\":\"\",\"localkeyfile\":\"\",\"useTransport\":false,\"maxChunkCount\":\"\",\"maxMessageSize\":\"\",\"receiveBufferSize\":\"\",\"sendBufferSize\":\"\",\"setstatusandtime\":false,\"keepsessionalive\":false,\"name\":\"\",\"x\":580,\"y\":500,\"wires\":[[\"28b575f06bbbe7a7\"],",[493,7833,7834],{},"\"139d346aab204f2f\"",[493,7836,7837],{},"\"3497d5566fb78f5f\"","]},{\"id\":\"4daa958d34c648c5\",\"type\":\"OpcUa-Item\",\"z\":\"ead97ed756a13a15\",\"item\":\"ns=5;s=Counter1\",\"datatype\":\"Int32\",\"value\":\"\",\"name\":\"\",\"x\":380,\"y\":480,\"wires\":[[\"6f5e2b1cbce15025\"]]},{\"id\":\"baa2733ca1fcb69d\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Add item\",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":200,\"y\":480,\"wires\":[[\"4daa958d34c648c5\"]]},{\"id\":\"dfd96a4dfe6330af\",\"type\":\"OpcUa-Item\",\"z\":\"ead97ed756a13a15\",\"item\":\"ns=5;s=Random1\",\"datatype\":\"Double\",\"value\":\"\",\"name\":\"\",\"x\":380,\"y\":520,\"wires\":[[\"6f5e2b1cbce15025\"]]},{\"id\":\"b8d5e40a98b1fb9f\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Add item\",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":200,\"y\":520,\"wires\":[[\"dfd96a4dfe6330af\"]]},{\"id\":\"3f63c46f499c3bca\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Read multiple items\",\"props\":",[493,7840,6630],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"readmultiple\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":370,\"y\":440,\"wires\":[[\"6f5e2b1cbce15025\"]]},{\"id\":\"75c7927996cf44c2\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Clear nodeId array\",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"clearitems\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":370,\"y\":560,\"wires\":[[\"6f5e2b1cbce15025\"]]},{\"id\":\"28b575f06bbbe7a7\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Tag Value\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":760,\"y\":460,\"wires\":",[493,7843],{},"},{\"id\":\"139d346aab204f2f\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Errors\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":750,\"y\":500,\"wires\":",[493,7846],{},"},{\"id\":\"3497d5566fb78f5f\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Raw Response\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":780,\"y\":540,\"wires\":",[493,7849],{},[1224,7851,7853],{"id":7852},"writing-values","Writing Values",[16,7855,7856],{},"In addition to reading data, OPC UA also allows you to write control signals or parameters to your equipment.",[3431,7858,7860],{"id":7859},"writing-a-single-tag","Writing a Single Tag",[16,7862,7863],{},"To write a single value:",[472,7865,7866,7871,7909,7917,7937,7939,7949],{},[56,7867,878,7868,7870],{},[59,7869,2495],{}," node onto the canvas (used to trigger the write operation).",[56,7872,4859,7873,7638,7875,7898,7900,7904,7906],{},[59,7874,7637],{},[53,7876,7877,7882,7893],{},[56,7878,7879,7881],{},[59,7880,7645],{},": Enter the target identifier.",[56,7883,7884,7886,7887,1447,7889,7892],{},[59,7885,7654],{},": Choose the appropriate type (e.g., ",[349,7888,7658],{},[349,7890,7891],{},"Double",").",[56,7894,7895,7897],{},[59,7896,708],{},": Enter the value to write.",[5136,7899],{},[650,7901],{"alt":7902,"dataZoomable":230,"src":7903},"Screenshot showing OPC UA Item node configuration for write operation","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fopcua-item-node-write.png",[5136,7905],{},[1529,7907,7908],{},"OPC UA Item node configured for a write operation",[56,7910,7911,7912,7914,7915,3116],{},"Connect the ",[59,7913,2495],{}," node to the ",[59,7916,7469],{},[56,7918,4859,7919,7677,7921,989,7923,285,7926,7928,7932,7934],{},[59,7920,4228],{},[59,7922,2525],{},[349,7924,7925],{},"WRITE",[5136,7927],{},[650,7929],{"alt":7930,"dataZoomable":230,"src":7931},"Screenshot showing OPC UA Client node with \"WRITE\" action selected","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fopcua-client-write-ops.png",[5136,7933],{},[1529,7935,7936],{},"OPC UA Client node with \"WRITE\" action selected",[56,7938,7690],{},[56,7940,7911,7941,7914,7943,7697,7945,7700,7947,3116],{},[59,7942,7469],{},[59,7944,7466],{},[59,7946,7466],{},[59,7948,2505],{},[56,7950,7714,7951,7953],{},[59,7952,2495],{}," button to trigger the write.",[16,7955,7956,7957,285],{},"The OPC UA Client node will confirm the operation with a status like ",[59,7958,7959],{},"\"values written\"",[16,7961,6586,7962,6641],{},[493,7963,7964,7965,3269,7968,7971,7972,7974,7975,7977,7978,7980,7981,5793],{},"{\"id\":\"c922a70d48ecba6f\",\"type\":\"OpcUa-Client\",\"z\":\"ead97ed756a13a15\",\"endpoint\":\"\",\"action\":\"write\",\"deadbandtype\":\"a\",\"deadbandvalue\":1,\"time\":10,\"timeUnit\":\"s\",\"certificate\":\"n\",\"localfile\":\"\",\"localkeyfile\":\"\",\"useTransport\":false,\"maxChunkCount\":\"\",\"maxMessageSize\":\"\",\"receiveBufferSize\":\"\",\"sendBufferSize\":\"\",\"setstatusandtime\":false,\"keepsessionalive\":false,\"name\":\"\",\"x\":520,\"y\":480,\"wires\":[[\"7eb010a4671ac181\"],",[493,7966,7967],{},"\"392bb1fd60c29baf\"",[493,7969,7970],{},"\"e9d279677dbc87e8\"","]},{\"id\":\"5ff1e3c2d5977a34\",\"type\":\"OpcUa-Item\",\"z\":\"ead97ed756a13a15\",\"item\":\"ns=5;s=Counter1\",\"datatype\":\"Int32\",\"value\":\"20\",\"name\":\"\",\"x\":340,\"y\":480,\"wires\":[[\"c922a70d48ecba6f\"]]},{\"id\":\"8cdd141dbdb350c7\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Write\",\"props\":",[493,7973,6630],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":190,\"y\":480,\"wires\":[[\"5ff1e3c2d5977a34\"]]},{\"id\":\"7eb010a4671ac181\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Tag Value\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":680,\"y\":440,\"wires\":",[493,7976],{},"},{\"id\":\"392bb1fd60c29baf\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Errors\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":670,\"y\":480,\"wires\":",[493,7979],{},"},{\"id\":\"e9d279677dbc87e8\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Raw Response\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":700,\"y\":520,\"wires\":",[493,7982],{},[3431,7984,7986],{"id":7985},"writing-multiple-tags","Writing Multiple Tags",[16,7988,7989],{},"To write multiple values at once, follow this pattern:",[472,7991,7992,8012,8015,8028,8035,8049,8055,8061,8067],{},[56,7993,4859,7994,7677,7996,989,7998,285,8001,8003,8007,8009],{},[59,7995,4228],{},[59,7997,2525],{},[349,7999,8000],{},"WRITE MULTIPLE",[5136,8002],{},[650,8004],{"alt":8005,"dataZoomable":230,"src":8006},"Screenshot showing OPC UA Client node with \"WRITE MULTIPLE\" action selected","\u002Fblog\u002F2025\u002F07\u002Fimages\u002Fopcua-client-write-multiple.png",[5136,8008],{},[1529,8010,8011],{},"OPC UA Client node configured for writing multiple values",[56,8013,8014],{},"Select the appropriate endpoint configuration.",[56,8016,8017,8018,8020,8021,1447,8023,1450,8025,8027],{},"Add multiple ",[59,8019,7637],{}," nodes, each configured with a ",[59,8022,7645],{},[59,8024,7654],{},[59,8026,708],{}," to be written.",[56,8029,4859,8030,8032,8033,3116],{},[59,8031,2495],{}," node for each ",[59,8034,7469],{},[56,8036,8037,8038,8040,8041,8043,8044,8046,8047,3116],{},"Connect each ",[59,8039,2495],{}," node to its corresponding ",[59,8042,7469],{}," node, then connect all ",[59,8045,7469],{}," nodes to the ",[59,8048,7466],{},[56,8050,4278,8051,7803,8053,3116],{},[59,8052,2505],{},[59,8054,7466],{},[56,8056,8057,8058,8060],{},"Deploy the flow and trigger all ",[59,8059,2495],{}," nodes to load the values.",[56,8062,8063,8064,285],{},"To execute the write operation, send a message with ",[349,8065,8066],{},"msg.topic = \"writemultiple\"",[56,8068,8069,8070,285],{},"To clear the stored items, send a message with ",[349,8071,7823],{},[16,8073,8074],{},"This setup allows you to prepare multiple tag values and write them all at once, giving you precise control through a single command.",[16,8076,6586,8077,6641],{},[493,8078,8079,8080,3269,8083,8086,8087,8089,8090,8092,8093,8095,8096,8098,8099,5793],{},"{\"id\":\"ed421a9.d6319e8\",\"type\":\"OpcUa-Client\",\"z\":\"ead97ed756a13a15\",\"endpoint\":\"\",\"action\":\"writemultiple\",\"deadbandtype\":\"a\",\"deadbandvalue\":1,\"time\":10,\"timeUnit\":\"s\",\"certificate\":\"n\",\"localfile\":\"\",\"localkeyfile\":\"\",\"useTransport\":false,\"maxChunkCount\":\"\",\"maxMessageSize\":\"\",\"receiveBufferSize\":\"\",\"sendBufferSize\":\"\",\"setstatusandtime\":false,\"keepsessionalive\":false,\"name\":\"\",\"x\":560,\"y\":420,\"wires\":[[\"b0788fb9285c48ea\"],",[493,8081,8082],{},"\"bde690208cbf2c4c\"",[493,8084,8085],{},"\"0883826b4a0ca030\"","]},{\"id\":\"96bd763.14a9308\",\"type\":\"OpcUa-Item\",\"z\":\"ead97ed756a13a15\",\"item\":\"ns=3;i=1007\",\"datatype\":\"Double\",\"value\":\"1.0\",\"name\":\"\",\"x\":360,\"y\":400,\"wires\":[[\"ed421a9.d6319e8\"]]},{\"id\":\"d8a68c7a.a73008\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Add item\",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":180,\"y\":400,\"wires\":[[\"96bd763.14a9308\"]]},{\"id\":\"8ae51c8c.20bd3\",\"type\":\"OpcUa-Item\",\"z\":\"ead97ed756a13a15\",\"item\":\"ns=3;i=1008\",\"datatype\":\"Int32\",\"value\":\"50\",\"name\":\"\",\"x\":360,\"y\":440,\"wires\":[[\"ed421a9.d6319e8\"]]},{\"id\":\"1335adce.7f46ba\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Add item\",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":180,\"y\":440,\"wires\":[[\"8ae51c8c.20bd3\"]]},{\"id\":\"2c050a3d.91f496\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Write multiple items\",\"props\":",[493,8088,6630],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"writemultiple\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":350,\"y\":360,\"wires\":[[\"ed421a9.d6319e8\"]]},{\"id\":\"690e4f9f.faeca\",\"type\":\"inject\",\"z\":\"ead97ed756a13a15\",\"name\":\"Clear nodeId array\",\"props\":",[493,8091,6630],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"clearitems\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":350,\"y\":480,\"wires\":[[\"ed421a9.d6319e8\"]]},{\"id\":\"b0788fb9285c48ea\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Tag Value\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":740,\"y\":380,\"wires\":",[493,8094],{},"},{\"id\":\"bde690208cbf2c4c\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Errors\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":730,\"y\":420,\"wires\":",[493,8097],{},"},{\"id\":\"0883826b4a0ca030\",\"type\":\"debug\",\"z\":\"ead97ed756a13a15\",\"name\":\"Raw Response\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":760,\"y\":460,\"wires\":",[493,8100],{},[26,8102,8104],{"id":8103},"whats-next","What’s Next",[16,8106,8107],{},"You’ve now mastered the fundamentals of OPC UA integration, connecting to servers, browsing tags, and reading or writing data. These core building blocks lay the foundation for powerful industrial automation.",[16,8109,8110,8111,8114],{},"In real deployments, you will want more than Inject nodes and debug panels. With ",[59,8112,8113],{},"FlowFuse Dashboard 2.0",", you can build full operator interfaces, live gauges, control buttons, trend charts, fully connected to your OPC UA data.",[16,8116,8117],{},"This guide covered the basics, but OPC UA offers far more. In the next article, we will explore:",[53,8119,8120,8123,8126,8129],{},[56,8121,8122],{},"Subscriptions for real-time monitoring without polling",[56,8124,8125],{},"Events and alarms directly from equipment",[56,8127,8128],{},"Historical data queries for trend analysis",[56,8130,8131],{},"Method calls to execute functions on your devices",[16,8133,8134,8135,8137],{},"When it is time to move beyond prototypes, ",[59,8136,284],{}," delivers what industrial systems truly need, remote device management, instant rollbacks with full version control, built-in team collaboration, and high availability you can trust.",[16,8139,8140],{},"If you’re ready to simplify your OPC UA integration and scale industrial workflows with Node-RED, [start your free trial]({% include \"sign-up-url.njk\" %}) of FlowFuse today.",[16,8142,8143,8144,8146],{},"OPC UA is one of several protocols FlowFuse uses to connect PLCs to MQTT, cloud platforms, and enterprise systems. See the ",[105,8145,1475],{"href":1474}," for EtherNet\u002FIP, Siemens S7, Modbus, and more.",{"title":230,"searchDepth":231,"depth":231,"links":8148},[8149,8156,8172],{"id":7354,"depth":234,"text":7355,"children":8150},[8151,8152,8153,8154,8155],{"id":7361,"depth":507,"text":7362},{"id":7368,"depth":507,"text":7369},{"id":7375,"depth":507,"text":7376},{"id":7382,"depth":507,"text":7383},{"id":7389,"depth":507,"text":7390},{"id":2895,"depth":234,"text":2896,"children":8157},[8158,8159,8162,8163,8164,8168],{"id":7404,"depth":507,"text":7405},{"id":7428,"depth":507,"text":7429,"children":8160},[8161],{"id":7435,"depth":231,"text":7436},{"id":7476,"depth":507,"text":7477},{"id":7546,"depth":507,"text":7547},{"id":7614,"depth":507,"text":7615,"children":8165},[8166,8167],{"id":7621,"depth":231,"text":7622},{"id":7754,"depth":231,"text":7755},{"id":7852,"depth":507,"text":7853,"children":8169},[8170,8171],{"id":7859,"depth":231,"text":7860},{"id":7985,"depth":231,"text":7986},{"id":8103,"depth":234,"text":8104},"2025-07-16","OPC UA tutorial: Connect Node-RED to industrial PLCs step-by-step. Configure Kepware endpoints, read\u002Fwrite Siemens S7 tags, browse Allen-Bradley data. Free guide.","blog\u002F2025\u002F07\u002Fimages\u002Fopcua-tutorial.png",{"keywords":8177,"excerpt":8178},"OPC UA Node-RED tutorial, connect PLC to Node-RED, OPC UA example, Node-RED industrial IoT, OPC UA browser Node-RED, read PLC data Node-RED, OPC UA client configuration, Kepware Node-RED, OPC UA port 4840, industrial automation tutorial",{"type":13,"value":8179},[8180],[16,8181,7306],{},"\u002Fblog\u002F2025\u002F07\u002Freading-and-writing-plc-data-using-opc-ua",{"title":7300,"description":8174},{"loc":8182},"blog\u002F2025\u002F07\u002Freading-and-writing-plc-data-using-opc-ua","A practical guide to accessing industrial data through OPC UA server gateways",[1518,8188,263],"opcua","OPC UA is the industry-standard protocol that provides a universal language for connecting PLCs, SCADA systems, HMIs, and enterprise applications from any vendor. This hands-on tutorial shows how to use Node-RED and FlowFuse to connect to any OPC UA server, browse available tags, and read and write real-time values from industrial equipment using the OPC UA Browser node for discovering Node IDs.","HmqpYuVb_fVnQD0uk4EXLMYTz-sUmN_pDO9PUfSoy1E",{"id":8192,"title":8193,"authors":8194,"body":8196,"cta":9405,"date":9408,"description":9409,"extension":248,"image":9410,"lastUpdated":9411,"meta":9412,"navigation":255,"path":9418,"seo":9419,"sitemap":9420,"stem":9421,"subtitle":9422,"tags":9423,"tldr":9425,"video":3,"__hash__":9426},"blog\u002Fblog\u002F2025\u002F01\u002Fintegrating-siemens-s7-plcs-with-node-red-guide.md","How to Read and Write Siemens S7 PLC Data, A Node-RED Guide (2026)",[11,8195],"stephen-mclaughlin",{"type":13,"value":8197,"toc":9391},[8198,8201,8204,8207,8211,8214,8219,8224,8232,8237,8245,8250,8259,8268,8273,8278,8282,8285,8288,8296,8299,8303,8314,8318,8337,8340,8344,8347,9029,9032,9041,9045,9048,9062,9070,9078,9086,9094,9102,9106,9109,9122,9130,9142,9146,9149,9156,9160,9163,9170,9173,9182,9185,9188,9191,9220,9228,9234,9237,9240,9243,9246,9254,9292,9301,9364,9366,9369,9377,9380,9382,9385],[16,8199,8200],{},"Siemens S7 PLCs are a staple in industrial automation, powering everything from basic control functions to complex, large-scale processes. However, integrating these PLCs with other systems for remote monitoring or data sharing can present challenges.",[16,8202,8203],{},"This is where Node-RED comes in, offering a user-friendly solution to seamlessly connect Siemens S7 PLCs with a variety of platforms. With its intuitive flow-based interface, Node-RED enables you to create custom workflows and dashboards, no deep technical expertise required.",[16,8205,8206],{},"Siemens S7 PLCs are typically programmed using TIA Portal, Siemens' integrated development environment, and communication with external systems usually relies on the S7 protocol (ISO over TCP\u002FIP). In this article, we’ll walk you through how to use Node-RED to read from and write to Siemens S7 PLCs via the S7 protocol, unlocking new possibilities for remote control and system integration in your industrial automation setup.",[26,8208,8210],{"id":8209},"prerequisite","Prerequisite",[16,8212,8213],{},"Before integrating your Siemens S7 PLC with Node-RED, make sure you have the following :",[472,8215,8216],{},[56,8217,8218],{},"Before downloading the ladder program and all configurations and settings to your PLC, make sure you have the following settings:",[53,8220,8221],{},[56,8222,8223],{},"Allow PUT\u002FGET Communication from remote partners.",[16,8225,8226,8230],{},[650,8227],{"alt":8228,"src":8229,"dataZoomable":230},"PUT\u002FGET Communication from remote partners is Allowed","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fallow-put-get-communication.png",[1529,8231,8228],{},[53,8233,8234],{},[56,8235,8236],{},"Provide full access to the PLC (no protection), allowing unrestricted access to data exchange.",[16,8238,8239,8243],{},[650,8240],{"alt":8241,"src":8242,"dataZoomable":230},"Providing complete access to the PLC","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fproviding-full-access-to-plc.png",[1529,8244,8241],{},[472,8246,8247],{"start":234},[56,8248,8249],{},"Ensure that the appropriate ladder program (or any other logic) is written according to your requirements and successfully downloaded to the PLC. However, before downloading, make sure the 'Optimized Block Access' option is disabled for the data block that your ladder program using.",[16,8251,8252,8256],{},[650,8253],{"alt":8254,"src":8255,"dataZoomable":230},"Untick 'Optimized Block Access'.","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Foptimized-block-access.png",[1529,8257,8258],{},"Untick 'Optimized Block Access.'",[472,8260,8261],{"start":507},[56,8262,8263,8264,8267],{},"Install Node-RED on the device that will communicate with the S7 PLC. You cannot install Node-RED directly on the S7 PLC, as PLCs are typically controllers, not computers. For example, you can use a device like the Revolutionary Pi to connect and transfer data across systems. Use the ",[105,8265,6763],{"href":8266},"\u002Fplatform\u002Fdevice-agent\u002F"," to install Node-RED on your device.",[53,8269,8270],{},[56,8271,8272],{},"Why FlowFuse Device Agent? It allows you to manage Node-RED remotely, enabling control, monitoring, and flow creation without the need for on-site visits. FlowFuse also offers a suite of enterprise-grade features such as collaboration, device management, and DevOps pipelines, which are essential in industrial environments. These features help streamline operations and ensure scalability in complex automation systems. [Sign up for free]({% include \"sign-up-url.njk\" %}) to get started.",[472,8274,8275],{"start":231},[56,8276,8277],{},"Verify that the device running Node-RED is in the same network as the PLC and can successfully ping the PLC. Also, a firewall should not block the S7 port (typically port 102).",[26,8279,8281],{"id":8280},"integrating-siemens-s7-plcs-with-node-red","Integrating Siemens S7 PLCs with Node-RED",[16,8283,8284],{},"Now that everything is set up, let's integrate your Siemens S7 PLC with Node-RED. In this article, I’ll demonstrate the process using a Siemens S7-1212C PLC. I’ve connected it to a stack\u002Ftower light and will walk you through how to write data to the PLC to control this light. Later, I’ll show you how to read data and reflect the status of the light.",[16,8286,8287],{},"My program in TIA Portal is structured as shown below, utilizing DB (Data Blocks) and Q (physical outputs) to control devices. However, Node-RED can retrieve almost all types of data from the PLC. The process is similar for most data types.",[16,8289,8290,8294],{},[650,8291],{"alt":8292,"src":8293},"Ladder Logic to Control Outputs for Managing Lights","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fladder-to-control-lights.png",[1529,8295,8292],{},[16,8297,8298],{},"Let’s break down what’s happening in the ladder logic above. First, we have open contacts, each with address variables defined in a separate Data Block. There are three open branches, each starting with an open contact. Each contact is connected to an output that alters the status of a Q physical address. Each Q corresponds to a physical output on the PLC, which is wired to the lights. When we change the status of a contact to \"true,\" it activates the corresponding light by altering the state of the Q output, which reflects the change in the physical output.",[1224,8300,8302],{"id":8301},"installing-the-s7-node","Installing the S7 Node",[16,8304,8305,8306,8308,8309,285],{},"To communicate from Node-RED to the PLC, we need to install the S7 node, which allows Node-RED to interface with Siemens S7 PLCs. In this article, we will be using ",[349,8307,2049],{},", which is quite popular. If this particular node is not suitable for your workflow you can find alternatives in the ",[105,8310,8313],{"href":8311,"rel":8312},"https:\u002F\u002Fflows.nodered.org\u002Fsearch?term=siemens&type=node",[1240],"Node-RED catalog",[3431,8315,8317],{"id":8316},"steps-to-install-the-s7-node","Steps to Install the S7 Node:",[472,8319,8320,8323,8326,8329,8335],{},[56,8321,8322],{},"Open your Node-RED editor in a web browser.",[56,8324,8325],{},"Open the main menu by clicking the three horizontal lines in the top-right corner.",[56,8327,8328],{},"Click \"Manage Palette\" from the menu.",[56,8330,8331,8332,8334],{},"Switch to the \"Install\" tab and type ",[349,8333,2049],{}," in the search field.",[56,8336,6870],{},[16,8338,8339],{},"Once the installation is complete, the S7 nodes will be available in your Node-RED palette, and you can start using it to communicate with your Siemens S7 PLC.",[1224,8341,8343],{"id":8342},"addressing-scheme-for-variables-in-node-red-with-the-s7-node","Addressing Scheme for Variables in Node-RED with the S7 Node",[16,8345,8346],{},"Before we start, it's important to note that the variables and their addresses configured on the S7 endpoint follow a slightly different addressing scheme compared to those used in Step 7 or the TIA Portal. Therefore, when adding variables to the S7 node in Node-RED, you must ensure that you follow the correct addressing format outlined in the table below.",[694,8348,8349,8372],{},[697,8350,8351],{},[700,8352,8353,8358,8363,8367],{},[703,8354,8355],{},[59,8356,8357],{},"Node-RED Address",[703,8359,8360],{},[59,8361,8362],{},"Step7 Equivalent",[703,8364,8365],{},[59,8366,7654],{},[703,8368,8369],{},[59,8370,8371],{},"Description",[710,8373,8374,8391,8409,8427,8445,8462,8480,8497,8515,8530,8546,8562,8578,8594,8610,8626,8643,8660,8677,8694,8711,8728,8744,8760,8776,8793,8810,8827,8843,8859,8875,8892,8908,8924,8939,8953,8967,8981,8997,9013],{},[700,8375,8376,8381,8386,8388],{},[715,8377,8378],{},[349,8379,8380],{},"DB5,X0.1",[715,8382,8383],{},[349,8384,8385],{},"DB5.DBX0.1",[715,8387,7658],{},[715,8389,8390],{},"Bit 1 of byte 0 in DB5",[700,8392,8393,8398,8403,8406],{},[715,8394,8395],{},[349,8396,8397],{},"DB23,BYTE1",[715,8399,8400],{},[349,8401,8402],{},"DB23.DBB1",[715,8404,8405],{},"Number (Byte)",[715,8407,8408],{},"Byte 1 (0-255) of DB23",[700,8410,8411,8416,8421,8424],{},[715,8412,8413],{},[349,8414,8415],{},"DB100,CHAR2",[715,8417,8418],{},[349,8419,8420],{},"DB100.DBB2",[715,8422,8423],{},"String",[715,8425,8426],{},"Byte 2 of DB100 as Char",[700,8428,8429,8434,8439,8442],{},[715,8430,8431],{},[349,8432,8433],{},"DB42,INT3",[715,8435,8436],{},[349,8437,8438],{},"DB42.DBW3",[715,8440,8441],{},"Number (16-bit)",[715,8443,8444],{},"Signed 16-bit number at byte 3 in DB42",[700,8446,8447,8452,8457,8459],{},[715,8448,8449],{},[349,8450,8451],{},"DB57,WORD4",[715,8453,8454],{},[349,8455,8456],{},"DB57.DBW4",[715,8458,8441],{},[715,8460,8461],{},"Unsigned 16-bit number at byte 4 in DB57",[700,8463,8464,8469,8474,8477],{},[715,8465,8466],{},[349,8467,8468],{},"DB13,DINT5",[715,8470,8471],{},[349,8472,8473],{},"DB13.DBD5",[715,8475,8476],{},"Number (32-bit)",[715,8478,8479],{},"Signed 32-bit number at byte 5 in DB13",[700,8481,8482,8487,8492,8494],{},[715,8483,8484],{},[349,8485,8486],{},"DB19,DWORD6",[715,8488,8489],{},[349,8490,8491],{},"DB19.DBD6",[715,8493,8476],{},[715,8495,8496],{},"Unsigned 32-bit number at byte 6 in DB19",[700,8498,8499,8504,8509,8512],{},[715,8500,8501],{},[349,8502,8503],{},"DB21,REAL7",[715,8505,8506],{},[349,8507,8508],{},"DB21.DBD7",[715,8510,8511],{},"Floating Point (32)",[715,8513,8514],{},"Floating point number at byte 7 in DB21",[700,8516,8517,8522,8525,8527],{},[715,8518,8519],{},[349,8520,8521],{},"DB2,S7.10*",[715,8523,8524],{},"-",[715,8526,8423],{},[715,8528,8529],{},"String (length 10) starting at byte 7 in DB2",[700,8531,8532,8537,8541,8543],{},[715,8533,8534],{},[349,8535,8536],{},"I1.0",[715,8538,8539],{},[349,8540,8536],{},[715,8542,7658],{},[715,8544,8545],{},"Bit 0 of byte 1 in input area",[700,8547,8548,8553,8557,8559],{},[715,8549,8550],{},[349,8551,8552],{},"Q2.1",[715,8554,8555],{},[349,8556,8552],{},[715,8558,7658],{},[715,8560,8561],{},"Bit 1 of byte 2 in output area",[700,8563,8564,8569,8573,8575],{},[715,8565,8566],{},[349,8567,8568],{},"M3.2",[715,8570,8571],{},[349,8572,8568],{},[715,8574,7658],{},[715,8576,8577],{},"Bit 2 of byte 3 in memory area",[700,8579,8580,8585,8589,8591],{},[715,8581,8582],{},[349,8583,8584],{},"IB4",[715,8586,8587],{},[349,8588,8584],{},[715,8590,8405],{},[715,8592,8593],{},"Byte 4 (0-255) in input area",[700,8595,8596,8601,8605,8607],{},[715,8597,8598],{},[349,8599,8600],{},"QB5",[715,8602,8603],{},[349,8604,8600],{},[715,8606,8405],{},[715,8608,8609],{},"Byte 5 (0-255) in output area",[700,8611,8612,8617,8621,8623],{},[715,8613,8614],{},[349,8615,8616],{},"MB6",[715,8618,8619],{},[349,8620,8616],{},[715,8622,8405],{},[715,8624,8625],{},"Byte 6 (0-255) in memory area",[700,8627,8628,8633,8638,8640],{},[715,8629,8630],{},[349,8631,8632],{},"IC7",[715,8634,8635],{},[349,8636,8637],{},"IB7",[715,8639,8423],{},[715,8641,8642],{},"Byte 7 of input area as Char",[700,8644,8645,8650,8655,8657],{},[715,8646,8647],{},[349,8648,8649],{},"QC8",[715,8651,8652],{},[349,8653,8654],{},"QB8",[715,8656,8423],{},[715,8658,8659],{},"Byte 8 of output area as Char",[700,8661,8662,8667,8672,8674],{},[715,8663,8664],{},[349,8665,8666],{},"MC9",[715,8668,8669],{},[349,8670,8671],{},"MB9",[715,8673,8423],{},[715,8675,8676],{},"Byte 9 of memory area as Char",[700,8678,8679,8684,8689,8691],{},[715,8680,8681],{},[349,8682,8683],{},"II10",[715,8685,8686],{},[349,8687,8688],{},"IW10",[715,8690,8441],{},[715,8692,8693],{},"Signed 16-bit number at byte 10 in input area",[700,8695,8696,8701,8706,8708],{},[715,8697,8698],{},[349,8699,8700],{},"QI12",[715,8702,8703],{},[349,8704,8705],{},"QW12",[715,8707,8441],{},[715,8709,8710],{},"Signed 16-bit number at byte 12 in output area",[700,8712,8713,8718,8723,8725],{},[715,8714,8715],{},[349,8716,8717],{},"MI14",[715,8719,8720],{},[349,8721,8722],{},"MW14",[715,8724,8441],{},[715,8726,8727],{},"Signed 16-bit number at byte 14 in memory area",[700,8729,8730,8735,8739,8741],{},[715,8731,8732],{},[349,8733,8734],{},"IW16",[715,8736,8737],{},[349,8738,8734],{},[715,8740,8441],{},[715,8742,8743],{},"Unsigned 16-bit number at byte 16 in input area",[700,8745,8746,8751,8755,8757],{},[715,8747,8748],{},[349,8749,8750],{},"QW18",[715,8752,8753],{},[349,8754,8750],{},[715,8756,8441],{},[715,8758,8759],{},"Unsigned 16-bit number at byte 18 in output area",[700,8761,8762,8767,8771,8773],{},[715,8763,8764],{},[349,8765,8766],{},"MW20",[715,8768,8769],{},[349,8770,8766],{},[715,8772,8441],{},[715,8774,8775],{},"Unsigned 16-bit number at byte 20 in memory area",[700,8777,8778,8783,8788,8790],{},[715,8779,8780],{},[349,8781,8782],{},"IDI22",[715,8784,8785],{},[349,8786,8787],{},"ID22",[715,8789,8476],{},[715,8791,8792],{},"Signed 32-bit number at byte 22 in input area",[700,8794,8795,8800,8805,8807],{},[715,8796,8797],{},[349,8798,8799],{},"QDI24",[715,8801,8802],{},[349,8803,8804],{},"QD24",[715,8806,8476],{},[715,8808,8809],{},"Signed 32-bit number at byte 24 in output area",[700,8811,8812,8817,8822,8824],{},[715,8813,8814],{},[349,8815,8816],{},"MDI26",[715,8818,8819],{},[349,8820,8821],{},"MD26",[715,8823,8476],{},[715,8825,8826],{},"Signed 32-bit number at byte 26 in memory area",[700,8828,8829,8834,8838,8840],{},[715,8830,8831],{},[349,8832,8833],{},"ID28",[715,8835,8836],{},[349,8837,8833],{},[715,8839,8476],{},[715,8841,8842],{},"Unsigned 32-bit number at byte 28 in input area",[700,8844,8845,8850,8854,8856],{},[715,8846,8847],{},[349,8848,8849],{},"QD30",[715,8851,8852],{},[349,8853,8849],{},[715,8855,8476],{},[715,8857,8858],{},"Unsigned 32-bit number at byte 30 in output area",[700,8860,8861,8866,8870,8872],{},[715,8862,8863],{},[349,8864,8865],{},"MD32",[715,8867,8868],{},[349,8869,8865],{},[715,8871,8476],{},[715,8873,8874],{},"Unsigned 32-bit number at byte 32 in memory area",[700,8876,8877,8882,8886,8889],{},[715,8878,8879],{},[349,8880,8881],{},"IR34",[715,8883,8884],{},[349,8885,8881],{},[715,8887,8888],{},"Floating Point",[715,8890,8891],{},"Floating point number at byte 34 in input area",[700,8893,8894,8899,8903,8905],{},[715,8895,8896],{},[349,8897,8898],{},"QR36",[715,8900,8901],{},[349,8902,8898],{},[715,8904,8888],{},[715,8906,8907],{},"Floating point number at byte 36 in output area",[700,8909,8910,8915,8919,8921],{},[715,8911,8912],{},[349,8913,8914],{},"MR38",[715,8916,8917],{},[349,8918,8914],{},[715,8920,8888],{},[715,8922,8923],{},"Floating point number at byte 38 in memory area",[700,8925,8926,8931,8933,8936],{},[715,8927,8928],{},[349,8929,8930],{},"DB1,DT0",[715,8932,8524],{},[715,8934,8935],{},"Date",[715,8937,8938],{},"Timestamp in DATE_AND_TIME format",[700,8940,8941,8946,8948,8950],{},[715,8942,8943],{},[349,8944,8945],{},"DB1,DTZ10",[715,8947,8524],{},[715,8949,8935],{},[715,8951,8952],{},"Timestamp in DATE_AND_TIME format (UTC)",[700,8954,8955,8960,8962,8964],{},[715,8956,8957],{},[349,8958,8959],{},"DB2,DTL2",[715,8961,8524],{},[715,8963,8935],{},[715,8965,8966],{},"Timestamp in DTL format",[700,8968,8969,8974,8976,8978],{},[715,8970,8971],{},[349,8972,8973],{},"DB2,DTLZ12",[715,8975,8524],{},[715,8977,8935],{},[715,8979,8980],{},"Timestamp in DTL format (UTC)",[700,8982,8983,8988,8992,8994],{},[715,8984,8985],{},[349,8986,8987],{},"DB57,RWORD4",[715,8989,8990],{},[349,8991,8456],{},[715,8993,8441],{},[715,8995,8996],{},"Unsigned 16-bit number, Little-Endian at byte 4",[700,8998,8999,9004,9008,9010],{},[715,9000,9001],{},[349,9002,9003],{},"DB13,RDI5",[715,9005,9006],{},[349,9007,8473],{},[715,9009,8476],{},[715,9011,9012],{},"Signed 32-bit number, Little-Endian at byte 5",[700,9014,9015,9020,9024,9026],{},[715,9016,9017],{},[349,9018,9019],{},"MRW20",[715,9021,9022],{},[349,9023,8766],{},[715,9025,8441],{},[715,9027,9028],{},"Unsigned 16-bit number, Little-Endian at byte 20",[16,9030,9031],{},"For example, consider that you have a ladder logic program in the TIA Portal with addresses like DB5.DBX0.0 and DB13.DBW4. You must adjust the address format slightly when you want to use these in the Node-RED S7 node. In Node-RED, DB5.DBX0.0 would be represented as DB5,X0.0 and DB13.DBW4 would be written as DB13,WORD4. Essentially, you look at the TIA Portal address, find the corresponding format in the Node-RED address column, and use that format in the S7 node configuration.",[16,9033,9034,9035,9040],{},"If you wanted integrate Siemens LOGO, please refer to the node's ",[105,9036,9039],{"href":9037,"rel":9038},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-s7",[1240],"README",", as the addressing differs.",[1224,9042,9044],{"id":9043},"configuring-the-s7-node-to-connect-to-the-plc","Configuring the S7 Node to Connect to the PLC",[16,9046,9047],{},"Now that you have all the necessary knowledge and setup, let's start by establishing a connection between Node-RED and your Siemens S7 PLC. The S7 node in Node-RED simplifies the process, making it easy to configure communication. Follow the steps below to connect and start interacting with your PLC",[472,9049,9050,9053,9056,9059],{},[56,9051,9052],{},"Drag the S7 node onto the Node-RED canvas.",[56,9054,9055],{},"Double-click on the S7 node and click on the \"+\" icon to add a PLC configuration.",[56,9057,9058],{},"Select \"Ethernet (ISO on TCP)\" as the transport protocol, then enter your PLC's IP address. The default port (102) is used for S7 communication, so leave it unchanged.",[56,9060,9061],{},"Set the Mode to \"Rack,\" then enter the Rack ID and Slot ID. These values can be found in the TIA Portal under the Device View tab on your configured device.",[16,9063,9064,9068],{},[650,9065],{"alt":9066,"src":9067,"dataZoomable":230},"Image showing window from where you will get the Rack No and Slot No","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fshowing-rack-and-slot.png",[1529,9069,9066],{},[472,9071,9072,9075],{"start":518},[56,9073,9074],{},"Enter the Cycle Time (interval for communication with the PLC) and Timeout Duration (maximum time to wait for a response).",[56,9076,9077],{},"Once done, switch to the Variables tab and add all the variables with the correct address and name you want to read or write.",[16,9079,9080,9084],{},[650,9081],{"alt":9082,"src":9083,"dataZoomable":230},"Adding Variables into s7 node","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fs7-config-variables.png",[1529,9085,9082],{},[472,9087,9088,9091],{"start":530},[56,9089,9090],{},"After adding the variables, click Add and then Done.",[56,9092,9093],{},"Deploy the flow by clicking the top-right Deploy button. Once deployed, the connection status will be displayed at the bottom of the node. If connected successfully, it will show a green squre with \"online\" status.",[16,9095,9096,9100],{},[650,9097],{"alt":9098,"src":9099,"dataZoomable":230},"Configuring S7 node for connection","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fs7-connection-configuration.png",[1529,9101,9098],{},[1224,9103,9105],{"id":9104},"writing-data-to-the-plc","Writing Data to the PLC",[16,9107,9108],{},"Now that you’ve configured the connection, it’s time to use Node-RED to write data to the PLC to control light.",[472,9110,9111,9114,9117,9120],{},[56,9112,9113],{},"Drag the s7-out node onto the canvas.",[56,9115,9116],{},"Double-click on the node and select the variable to which you want to update or write a value.",[56,9118,9119],{},"Select the PLC configuration that we have added.",[56,9121,4392],{},[16,9123,9124,9128],{},[650,9125],{"alt":9126,"src":9127,"dataZoomable":230},"Configuring S7-out Node to write data to plc","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fconfiguring-s7-out-node.png",[1529,9129,9126],{},[472,9131,9132,9139],{"start":518},[56,9133,9134,9135,9138],{},"The node is now ready to write data to the PLC. You can use standard Node-RED nodes like Inject, Change, or Function to create a workflow that sends the data. Ensure the data type matches the configuration set in the PLC program. For example, in my ladder logic, I need to modify the status of individual open contacts, each with its own address, such as DB1.DBX0.0, DB1.DBX0.1, and DB1.DBX0.2, to control the tower lights. Setting these contacts to TRUE will turn on the red, yellow, and green lights, respectively. You can send the data using the nodes I’ve mentioned, or you can build a custom dashboard with ",[105,9136,7044],{"href":9137},"\u002Fplatform\u002Fdashboard\u002F"," for easier interaction.",[56,9140,9141],{},"Once your flow is set up and the s7-out node for each variable is configured, click Deploy in the top-right corner to activate the flow.",[950,9143],{"videoid":9144,"params":2732,"style":9145,"title":2734},"AilWMNPzP1Q","width: 704px; height: 100%;",[16,9147,9148],{},"In the video above, the dashboard interface is built to control the stack light. At the end of this article, I will provide the complete flow for you to download.",[16,9150,9151,9152,285],{},"If you're building a dashboard, keep in mind that while you can create it on Node-RED within the remote instance on FlowFuse Device Agent, you won’t be able to access it remotely across the editor tunnel. You can of course access it locally on the device or on the local LAN. For this demonstration, I wish to access the dashboard remotely across the internet and so I will create the dashboard in a hosted instance of Node-RED and use the FlowFuse Projects nodes to simply and securely pass the necessary values to and from the remote Node-RED instance. For more details on how to set this up, check out our article: ",[105,9153,9155],{"href":9154},"\u002Fblog\u002F2024\u002F10\u002Fexploring-flowfuse-project-nodes\u002F","Exploring FlowFuse Project Nodes",[1224,9157,9159],{"id":9158},"reading-data-from-the-plc","Reading Data from the PLC",[16,9161,9162],{},"Now that we’ve covered how to write data to your Siemens S7 PLC, let's move on to reading data from it. Node-RED makes it easy to retrieve important information such as the status of inputs, outputs, or internal memory. By pulling this data into your workflows or visualizing it on a dashboard, you can monitor key parameters in real time and gain valuable insights.",[16,9164,9165,9166,285],{},"However, before we dive in, it's important to consider that reading individual data points one by one in large-scale manufacturing systems can lead to delays. This approach may not be efficient, especially when dealing with a large number of data points. For more information on these challenges and potential solutions, you can refer to this article: ",[105,9167,9169],{"href":9168},"\u002Fblog\u002F2023\u002F09\u002Fmodernize-your-legacy-industrial-data-part2\u002F","Modernize Your Legacy Industrial Data - Part 2",[16,9171,9172],{},"To address this issue, you can optimize data retrieval by storing output status values in a single word or double word within the PLC. For our example, I have created a custom function in my program that assigns the output values to individual bits of the word.",[16,9174,9175,9179],{},[650,9176],{"alt":9177,"src":9178,"dataZoomable":230},"Ladder diagram showing a custom function that stores the status of outputs in a single word within the PLC.","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fcustom-function-storing-bits-in-word.png",[1529,9180,9181],{},"Custom ladder diagram function storing output statuses in a single word for optimized data retrieval.",[16,9183,9184],{},"There are several ways to implement this, and depending on your system’s needs, some methods may be more efficient than others. In this case, the output values are stored in a single word within the PLC, as shown in the ladder diagram above. This is not the only correct method, it's simply one approach that works for this particular scenario. Feel free to adapt or explore other methods that might better suit your setup.",[16,9186,9187],{},"Additionally, if the data you’re reading is mission-critical and you can't afford to lose any, consider using a FIFO stack or buffer in your PLC program. This method ensures that even if there is a network outage or computer problem, no data is lost as it will remain siting in the stack until your Node-RED is back on line and retrieves it.  This ensures no gaps or interruptions in your data and guarantees data integrity.",[16,9189,9190],{},"Now, let’s begin reading the data from the PLC.",[472,9192,9193,9198,9201,9204,9214,9217],{},[56,9194,2961,9195,3231],{},[349,9196,9197],{},"s7-in",[56,9199,9200],{},"Double-click on the node to open the configuration and select the appropriate PLC configuration from the list of available connections.",[56,9202,9203],{},"Choose the appropriate mode based on your requirements. If you want to read only one variable, select \"Single Variable Mode\". In this mode, the \"Variable\" dropdown will allow you to select only a single variable at a time. If you need to read multiple variables, you can select \"All Variables\" mode, but be aware that the node might still process each request sequentially, depending on its internal workings (which is not fully documented). This can be inefficient when dealing with hundreds of variables.",[56,9205,9206,9207,9210,9211,285],{},"Choose the variable that corresponds to the word or double word containing all the data points you want to read. For example, if you’ve configured the word in the PLC as ",[349,9208,9209],{},"DB.DBW2",", the format in the s7-in node will be ",[349,9212,9213],{},"DB,WORD2",[56,9215,9216],{},"Enable the \"Emit only when value changes (diff)\" option to ensure that the node only triggers when the value of the variable changes, reducing unnecessary reads and improving efficiency.",[56,9218,9219],{},"Once your configuration is set, click \"Done\" and then deploy the flow to start reading data from the PLC.",[16,9221,9222,9226],{},[650,9223],{"alt":9224,"src":9225,"dataZoomable":230},"Configuring S7-in Node to Read data from plc","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fconfiguring-s7-in-node.png",[1529,9227,9224],{},[16,9229,9230,9231,9233],{},"You can add a \"Debug\" node to the ",[349,9232,9197],{}," node's output to verify that the data is being read correctly.",[16,9235,9236],{},"Once you see the printed data, you might be surprised, or perhaps you already expected this: since the word data type we're reading is not directly available in Node.js or Node-RED, we'll receive it as an integer. But don't worry, you can convert it into the format that suits your needs using node-red-contrib-buffer-parser. In this integer scenario, you'll need to shift the bits or extract individual values to match your desired output, such as isolating specific bits to represent different statuses or control points. The flow provided at the end demonstrates the implementation of this conversion.",[16,9238,9239],{},"Now that you have the desired format for your output data, you may want to build a dashboard interface with LEDs, gauges, or charts to monitor and visualize the data you've retrieved. You can use the FlowFuse Dashboard, as suggested earlier.",[16,9241,9242],{},"The video below shows the updated dashboard interface used to monitor the stack light LED status:",[950,9244],{"videoid":9245,"params":2732,"style":9145,"title":2734},"Nlyk_BATKGE",[16,9247,9248,9249,811,9251,9253],{},"Here is the flow you can import into your FlowFuse remote instance and deploy. Ensure that you have installed ",[349,9250,2049],{},[349,9252,5220],{},". This flow includes S7 nodes for interacting with the S7 PLC and Project nodes for communicating with the FlowFuse hosted instance, where you will build the dashboard.",[16,9255,9256,9257,6641],{},"{% renderFlow %}\n",[493,9258,9259,9260,9263,9264,9266,9267,9269,9270,9272,9273,9276,9277,9280,9281,9283,9284,9287,9288,9291],{},"{\"id\":\"0ffc8c2703b5e059\",\"type\":\"group\",\"z\":\"FFF0000000000001\",\"style\":{\"stroke\":\"#b2b3bd\",\"stroke-opacity\":\"1\",\"fill\":\"#f2f3fb\",\"fill-opacity\":\"0.5\",\"label\":true,\"label-position\":\"nw\",\"color\":\"#32333b\"},\"nodes\":",[493,9261,9262],{},"\"061313277591a004\",\"a8499bc2443f0bd9\",\"2974dd47fda54b9c\",\"4c009f6076f47eb6\",\"f4378d1e7c268e1e\",\"63abd67743263739\"",",\"x\":54,\"y\":99,\"w\":732,\"h\":202},{\"id\":\"061313277591a004\",\"type\":\"s7 out\",\"z\":\"FFF0000000000001\",\"g\":\"0ffc8c2703b5e059\",\"endpoint\":\"f2f06ce027c97e4d\",\"variable\":\"Button_1\",\"name\":\"Button to Turn the RED Light ON\",\"x\":620,\"y\":140,\"wires\":",[493,9265],{},"},{\"id\":\"a8499bc2443f0bd9\",\"type\":\"s7 out\",\"z\":\"FFF0000000000001\",\"g\":\"0ffc8c2703b5e059\",\"endpoint\":\"f2f06ce027c97e4d\",\"variable\":\"Button_2\",\"name\":\"Button to turn the Yellow light ON\",\"x\":620,\"y\":200,\"wires\":",[493,9268],{},"},{\"id\":\"2974dd47fda54b9c\",\"type\":\"s7 out\",\"z\":\"FFF0000000000001\",\"g\":\"0ffc8c2703b5e059\",\"endpoint\":\"f2f06ce027c97e4d\",\"variable\":\"Button_3\",\"name\":\"Button to turn Green light  ON\",\"x\":610,\"y\":260,\"wires\":",[493,9271],{},"},{\"id\":\"4c009f6076f47eb6\",\"type\":\"project link in\",\"z\":\"FFF0000000000001\",\"g\":\"0ffc8c2703b5e059\",\"name\":\"Project in node to control the red light\",\"project\":\"all\",\"broadcast\":true,\"topic\":\"light_control_red\",\"x\":230,\"y\":140,\"wires\":[[\"061313277591a004\"]]},{\"id\":\"f4378d1e7c268e1e\",\"type\":\"project link in\",\"z\":\"FFF0000000000001\",\"g\":\"0ffc8c2703b5e059\",\"name\":\"Project in node to control the yellow light\",\"project\":\"all\",\"broadcast\":true,\"topic\":\"light_control_yellow\",\"x\":240,\"y\":200,\"wires\":[[\"a8499bc2443f0bd9\"]]},{\"id\":\"63abd67743263739\",\"type\":\"project link in\",\"z\":\"FFF0000000000001\",\"g\":\"0ffc8c2703b5e059\",\"name\":\"Project in node to control the green light\",\"project\":\"all\",\"broadcast\":true,\"topic\":\"light_control_green\",\"x\":240,\"y\":260,\"wires\":[[\"2974dd47fda54b9c\"]]},{\"id\":\"f2f06ce027c97e4d\",\"type\":\"s7 endpoint\",\"transport\":\"iso-on-tcp\",\"address\":\"192.168.1.6\",\"port\":\"102\",\"rack\":\"0\",\"slot\":\"1\",\"localtsaphi\":\"01\",\"localtsaplo\":\"00\",\"remotetsaphi\":\"01\",\"remotetsaplo\":\"00\",\"connmode\":\"rack-slot\",\"adapter\":\"\",\"busaddr\":\"2\",\"cycletime\":\"1000\",\"timeout\":\"2000\",\"name\":\"S7 Connection Configuration\",\"vartable\":",[493,9274,9275],{},"{\"addr\":\"DB1,X0.0\",\"name\":\"Button_1\"},{\"addr\":\"DB1,X0.1\",\"name\":\"Button_2\"},{\"addr\":\"DB1,X0.2\",\"name\":\"Button_3\"},{\"addr\":\"DB1,WORD2\",\"name\":\"LightStatus\"}","},{\"id\":\"23fd40630dbef712\",\"type\":\"group\",\"z\":\"FFF0000000000001\",\"style\":{\"stroke\":\"#b2b3bd\",\"stroke-opacity\":\"1\",\"fill\":\"#f2f3fb\",\"fill-opacity\":\"0.5\",\"label\":true,\"label-position\":\"nw\",\"color\":\"#32333b\"},\"nodes\":",[493,9278,9279],{},"\"a45637418005d0e5\",\"a8ea1622d1fad4ba\",\"8d9a9dc4183a778e\",\"d60a74a5430df7ae\"",",\"x\":54,\"y\":339,\"w\":972,\"h\":82},{\"id\":\"a45637418005d0e5\",\"type\":\"s7 in\",\"z\":\"FFF0000000000001\",\"g\":\"23fd40630dbef712\",\"endpoint\":\"f2f06ce027c97e4d\",\"mode\":\"single\",\"variable\":\"LightStatus\",\"diff\":true,\"name\":\"\",\"x\":150,\"y\":380,\"wires\":[[\"d60a74a5430df7ae\"]]},{\"id\":\"a8ea1622d1fad4ba\",\"type\":\"project link out\",\"z\":\"FFF0000000000001\",\"g\":\"23fd40630dbef712\",\"name\":\"project out node to send the light status\",\"mode\":\"link\",\"broadcast\":true,\"project\":\"c51f38c2-6c80-442a-a9e2-10ddd68fb606\",\"topic\":\"light_status\",\"x\":840,\"y\":380,\"wires\":",[493,9282],{},"},{\"id\":\"8d9a9dc4183a778e\",\"type\":\"buffer-parser\",\"z\":\"FFF0000000000001\",\"g\":\"23fd40630dbef712\",\"name\":\"\",\"data\":\"payload\",\"dataType\":\"msg\",\"specification\":\"spec\",\"specificationType\":\"ui\",\"items\":",[493,9285,9286],{},"{\"type\":\"bool\",\"name\":\"red\",\"offset\":0,\"length\":1,\"offsetbit\":0,\"scale\":\"1\",\"mask\":\"\"},{\"type\":\"bool\",\"name\":\"yellow\",\"offset\":0,\"length\":1,\"offsetbit\":1,\"scale\":\"1\",\"mask\":\"\"},{\"type\":\"bool\",\"name\":\"green\",\"offset\":0,\"length\":1,\"offsetbit\":2,\"scale\":\"1\",\"mask\":\"\"},{\"type\":\"bool\",\"name\":\"all\",\"offset\":0,\"length\":16,\"offsetbit\":0,\"scale\":\"1\",\"mask\":\"\"}",",\"swap1\":\"\",\"swap2\":\"\",\"swap3\":\"\",\"swap1Type\":\"swap\",\"swap2Type\":\"swap\",\"swap3Type\":\"swap\",\"msgProperty\":\"payload\",\"msgPropertyType\":\"str\",\"resultType\":\"keyvalue\",\"resultTypeType\":\"return\",\"multipleResult\":false,\"fanOutMultipleResult\":false,\"setTopic\":true,\"outputs\":1,\"x\":530,\"y\":380,\"wires\":[[\"a8ea1622d1fad4ba\"]]},{\"id\":\"d60a74a5430df7ae\",\"type\":\"buffer-maker\",\"z\":\"FFF0000000000001\",\"g\":\"23fd40630dbef712\",\"name\":\"\",\"specification\":\"spec\",\"specificationType\":\"ui\",\"items\":",[493,9289,9290],{},"{\"name\":\"1stword\",\"type\":\"uint16le\",\"length\":1,\"dataType\":\"msg\",\"data\":\"payload\"}",",\"swap1\":\"\",\"swap2\":\"\",\"swap3\":\"\",\"swap1Type\":\"swap\",\"swap2Type\":\"swap\",\"swap3Type\":\"swap\",\"msgProperty\":\"payload\",\"msgPropertyType\":\"str\",\"x\":330,\"y\":380,\"wires\":[[\"8d9a9dc4183a778e\"]]}",[16,9293,9294,9295,811,9297,9300],{},"Below is the flow that you can import and deploy into the hosted instance created on FlowFuse. With this flow, you'll have a dashboard to control and monitor the tower lights. Just make sure you have installed ",[349,9296,4321],{},[349,9298,9299],{},"@flowfuse\u002Fnode-red-dashboard-2-ui-led",", and ensure the hosted instance is in the same FlowFuse team as your remote instance.",[16,9302,9256,9303,6641],{},[493,9304,9305,9306,9309,9310,9312,9313,9315,9316,9318,9319,9322,9323,9326,9327,9330,9331,9334,9335,9337,9338,9341,9342,9344,9345,9348,9349,9351,9352,9355,9356,9359,9360,9363],{},"{\"id\":\"1f56099d53798b99\",\"type\":\"group\",\"z\":\"eb351e503901d04f\",\"style\":{\"stroke\":\"#b2b3bd\",\"stroke-opacity\":\"1\",\"fill\":\"#f2f3fb\",\"fill-opacity\":\"0.5\",\"label\":true,\"label-position\":\"nw\",\"color\":\"#32333b\"},\"nodes\":",[493,9307,9308],{},"\"1e6a379c83bac6b4\",\"f015125886fec5a6\",\"76c696f160db3ca2\",\"1974cfc417898151\",\"9c503fe31081dc2f\",\"9501e2eb7690a0b5\"",",\"x\":74,\"y\":79,\"w\":652,\"h\":202},{\"id\":\"1e6a379c83bac6b4\",\"type\":\"ui-button\",\"z\":\"eb351e503901d04f\",\"g\":\"1f56099d53798b99\",\"group\":\"d4102809d229cb95\",\"name\":\"\",\"label\":\"YELLOW\",\"order\":5,\"width\":\"3\",\"height\":\"2\",\"emulateClick\":false,\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"iconPosition\":\"left\",\"payload\":\"\",\"payloadType\":\"str\",\"topic\":\"topic\",\"topicType\":\"msg\",\"buttonColor\":\"yellow\",\"textColor\":\"\",\"iconColor\":\"\",\"enableClick\":false,\"enablePointerdown\":true,\"pointerdownPayload\":\"1\",\"pointerdownPayloadType\":\"num\",\"enablePointerup\":true,\"pointerupPayload\":\"0\",\"pointerupPayloadType\":\"num\",\"x\":160,\"y\":180,\"wires\":[[\"1974cfc417898151\"]]},{\"id\":\"f015125886fec5a6\",\"type\":\"ui-button\",\"z\":\"eb351e503901d04f\",\"g\":\"1f56099d53798b99\",\"group\":\"d4102809d229cb95\",\"name\":\"\",\"label\":\"RED\",\"order\":4,\"width\":\"3\",\"height\":\"2\",\"emulateClick\":false,\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"iconPosition\":\"left\",\"payload\":\"\",\"payloadType\":\"str\",\"topic\":\"topic\",\"topicType\":\"msg\",\"buttonColor\":\"red\",\"textColor\":\"\",\"iconColor\":\"\",\"enableClick\":false,\"enablePointerdown\":true,\"pointerdownPayload\":\"1\",\"pointerdownPayloadType\":\"num\",\"enablePointerup\":true,\"pointerupPayload\":\"0\",\"pointerupPayloadType\":\"num\",\"x\":150,\"y\":120,\"wires\":[[\"9501e2eb7690a0b5\"]]},{\"id\":\"76c696f160db3ca2\",\"type\":\"ui-button\",\"z\":\"eb351e503901d04f\",\"g\":\"1f56099d53798b99\",\"group\":\"d4102809d229cb95\",\"name\":\"\",\"label\":\"GREEN\",\"order\":6,\"width\":\"3\",\"height\":\"2\",\"emulateClick\":false,\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"iconPosition\":\"left\",\"payload\":\"\",\"payloadType\":\"str\",\"topic\":\"topic\",\"topicType\":\"msg\",\"buttonColor\":\"green\",\"textColor\":\"\",\"iconColor\":\"\",\"enableClick\":false,\"enablePointerdown\":true,\"pointerdownPayload\":\"1\",\"pointerdownPayloadType\":\"num\",\"enablePointerup\":true,\"pointerupPayload\":\"0\",\"pointerupPayloadType\":\"num\",\"x\":160,\"y\":240,\"wires\":[[\"9c503fe31081dc2f\"]]},{\"id\":\"1974cfc417898151\",\"type\":\"project link out\",\"z\":\"eb351e503901d04f\",\"g\":\"1f56099d53798b99\",\"name\":\"Project out node to control the yellow light\",\"mode\":\"link\",\"broadcast\":true,\"project\":\"c51f38c2-6c80-442a-a9e2-10ddd68fb606\",\"topic\":\"light_control_yellow\",\"x\":530,\"y\":180,\"wires\":",[493,9311],{},"},{\"id\":\"9c503fe31081dc2f\",\"type\":\"project link out\",\"z\":\"eb351e503901d04f\",\"g\":\"1f56099d53798b99\",\"name\":\"Project out node to control the green light\",\"mode\":\"link\",\"broadcast\":true,\"project\":\"c51f38c2-6c80-442a-a9e2-10ddd68fb606\",\"topic\":\"light_control_green\",\"x\":520,\"y\":240,\"wires\":",[493,9314],{},"},{\"id\":\"9501e2eb7690a0b5\",\"type\":\"project link out\",\"z\":\"eb351e503901d04f\",\"g\":\"1f56099d53798b99\",\"name\":\"Project out node to control the red light\",\"mode\":\"link\",\"broadcast\":true,\"project\":\"c51f38c2-6c80-442a-a9e2-10ddd68fb606\",\"topic\":\"light_control_red\",\"x\":520,\"y\":120,\"wires\":",[493,9317],{},"},{\"id\":\"d4102809d229cb95\",\"type\":\"ui-group\",\"name\":\"Group 1\",\"page\":\"62085b96f178f643\",\"width\":\"3\",\"height\":1,\"order\":1,\"showTitle\":false,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\",\"groupType\":\"default\"},{\"id\":\"62085b96f178f643\",\"type\":\"ui-page\",\"name\":\"Page 1\",\"ui\":\"02c25e8a30f9379d\",\"path\":\"\u002Fpage1\",\"icon\":\"home\",\"layout\":\"notebook\",\"theme\":\"f6f5e7ae33bf6878\",\"breakpoints\":",[493,9320,9321],{},"{\"name\":\"Default\",\"px\":\"0\",\"cols\":\"3\"},{\"name\":\"Tablet\",\"px\":\"576\",\"cols\":\"6\"},{\"name\":\"Small Desktop\",\"px\":\"768\",\"cols\":\"9\"},{\"name\":\"Desktop\",\"px\":\"1024\",\"cols\":\"12\"}",",\"order\":1,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"02c25e8a30f9379d\",\"type\":\"ui-base\",\"name\":\"My Dashboard\",\"path\":\"\u002Fdashboard\",\"appIcon\":\"\",\"includeClientData\":true,\"acceptsClientConfig\":",[493,9324,9325],{},"\"ui-notification\",\"ui-control\"",",\"showPathInSidebar\":false,\"showPageTitle\":true,\"navigationStyle\":\"default\",\"titleBarStyle\":\"hidden\"},{\"id\":\"f6f5e7ae33bf6878\",\"type\":\"ui-theme\",\"name\":\"Default Theme\",\"colors\":{\"surface\":\"#ffffff\",\"primary\":\"#0094ce\",\"bgPage\":\"#1a1a1a\",\"groupBg\":\"#000000\",\"groupOutline\":\"#000000\"},\"sizes\":{\"density\":\"default\",\"pagePadding\":\"12px\",\"groupGap\":\"12px\",\"groupBorderRadius\":\"4px\",\"widgetGap\":\"12px\"}},{\"id\":\"82cc6997fddd0b4b\",\"type\":\"group\",\"z\":\"eb351e503901d04f\",\"style\":{\"stroke\":\"#b2b3bd\",\"stroke-opacity\":\"1\",\"fill\":\"#f2f3fb\",\"fill-opacity\":\"0.5\",\"label\":true,\"label-position\":\"nw\",\"color\":\"#32333b\"},\"nodes\":",[493,9328,9329],{},"\"d163a7ab23f7458f\",\"20d211683534362b\",\"b1477193956e591b\",\"fb8801a4accc3c15\",\"2f62948afcfde259\",\"6966f129e718d20a\",\"a5cecf8e8adf6eef\"",",\"x\":74,\"y\":299,\"w\":872,\"h\":202},{\"id\":\"d163a7ab23f7458f\",\"type\":\"ui-led\",\"z\":\"eb351e503901d04f\",\"g\":\"82cc6997fddd0b4b\",\"name\":\"Status of RED light\",\"group\":\"d4102809d229cb95\",\"order\":1,\"width\":\"1\",\"height\":\"3\",\"label\":\"\",\"labelPlacement\":\"left\",\"labelAlignment\":\"left\",\"states\":",[493,9332,9333],{},"{\"value\":\"true\",\"valueType\":\"bool\",\"color\":\"#ff0000\"},{\"value\":\"false\",\"valueType\":\"bool\",\"color\":\"#787878\"}",",\"allowColorForValueInMessage\":false,\"shape\":\"circle\",\"showBorder\":true,\"showGlow\":true,\"x\":810,\"y\":340,\"wires\":",[493,9336],{},"},{\"id\":\"20d211683534362b\",\"type\":\"ui-led\",\"z\":\"eb351e503901d04f\",\"g\":\"82cc6997fddd0b4b\",\"name\":\"Status of Yellow light\",\"group\":\"d4102809d229cb95\",\"order\":2,\"width\":\"1\",\"height\":\"3\",\"label\":\"\",\"labelPlacement\":\"left\",\"labelAlignment\":\"left\",\"states\":",[493,9339,9340],{},"{\"value\":\"true\",\"valueType\":\"bool\",\"color\":\"#c8ff00\"},{\"value\":\"false\",\"valueType\":\"bool\",\"color\":\"#787878\"}",",\"allowColorForValueInMessage\":false,\"shape\":\"circle\",\"showBorder\":true,\"showGlow\":true,\"x\":820,\"y\":400,\"wires\":",[493,9343],{},"},{\"id\":\"b1477193956e591b\",\"type\":\"ui-led\",\"z\":\"eb351e503901d04f\",\"g\":\"82cc6997fddd0b4b\",\"name\":\"Status of Green light\",\"group\":\"d4102809d229cb95\",\"order\":3,\"width\":\"1\",\"height\":\"3\",\"label\":\"\",\"labelPlacement\":\"left\",\"labelAlignment\":\"left\",\"states\":",[493,9346,9347],{},"{\"value\":\"true\",\"valueType\":\"bool\",\"color\":\"#41891a\"},{\"value\":\"false\",\"valueType\":\"bool\",\"color\":\"#787878\"}",",\"allowColorForValueInMessage\":false,\"shape\":\"circle\",\"showBorder\":true,\"showGlow\":true,\"x\":820,\"y\":460,\"wires\":",[493,9350],{},"},{\"id\":\"fb8801a4accc3c15\",\"type\":\"change\",\"z\":\"eb351e503901d04f\",\"g\":\"82cc6997fddd0b4b\",\"name\":\"\",\"rules\":",[493,9353,9354],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"payload.red\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":600,\"y\":340,\"wires\":[[\"d163a7ab23f7458f\"]]},{\"id\":\"2f62948afcfde259\",\"type\":\"change\",\"z\":\"eb351e503901d04f\",\"g\":\"82cc6997fddd0b4b\",\"name\":\"\",\"rules\":",[493,9357,9358],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"payload.yellow\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":600,\"y\":400,\"wires\":[[\"20d211683534362b\"]]},{\"id\":\"6966f129e718d20a\",\"type\":\"change\",\"z\":\"eb351e503901d04f\",\"g\":\"82cc6997fddd0b4b\",\"name\":\"\",\"rules\":",[493,9361,9362],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"payload.green\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":600,\"y\":460,\"wires\":[[\"b1477193956e591b\"]]},{\"id\":\"a5cecf8e8adf6eef\",\"type\":\"project link in\",\"z\":\"eb351e503901d04f\",\"g\":\"82cc6997fddd0b4b\",\"name\":\"project in node to receive the light status\",\"project\":\"all\",\"broadcast\":true,\"topic\":\"light_status\",\"x\":260,\"y\":400,\"wires\":[[\"fb8801a4accc3c15\",\"2f62948afcfde259\",\"6966f129e718d20a\"]]}",[26,9365,1133],{"id":1132},[16,9367,9368],{},"When you try to establish a connection with the PLC, you may encounter the following error. This error occurs because your device has established the connection but is unable to communicate. To resolve this issue, ensure that you have configured all the settings mentioned in the prerequisites. If the problem persists, it could be because your PLC and the device running Node-RED are on different networks.",[16,9370,9371,9375],{},[650,9372],{"alt":9373,"src":9374,"dataZoomable":230},"\"Error: This service is not implemented on the modeul or frame error was reported\"","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Ferror.png",[1529,9376,9373],{},[16,9378,9379],{},"Make sure the IP addresses of your device and PLC are in the same subnet. If the PLC is connected to the internet via a router, all devices (PLC, Node-RED device, and router) should have IP addresses within the same subnet. For example, if your PLC has the address 192.168.1.1, ensure that the other devices have IP addresses in the range 192.168.1.x.",[26,9381,1456],{"id":1455},[16,9383,9384],{},"Integrating Siemens S7 PLCs with Node-RED opens up powerful automation possibilities with minimal complexity. By following the steps outlined in this guide, you can easily connect your PLC to Node-RED, control devices, and visualize real-time data on dashboards. Whether you're writing data to control outputs or reading sensor values, Node-RED offers a flexible, user-friendly platform for industrial automation.",[16,9386,9387,9388,9390],{},"Beyond Siemens S7, FlowFuse connects Allen-Bradley, Omron, Beckhoff, and any Modbus or OPC UA-enabled PLC to MQTT, cloud, and enterprise systems. See the ",[105,9389,1475],{"href":1474}," for all supported protocols and use cases.",{"title":230,"searchDepth":231,"depth":231,"links":9392},[9393,9394,9403,9404],{"id":8209,"depth":234,"text":8210},{"id":8280,"depth":234,"text":8281,"children":9395},[9396,9399,9400,9401,9402],{"id":8301,"depth":507,"text":8302,"children":9397},[9398],{"id":8316,"depth":231,"text":8317},{"id":8342,"depth":507,"text":8343},{"id":9043,"depth":507,"text":9044},{"id":9104,"depth":507,"text":9105},{"id":9158,"depth":507,"text":9159},{"id":1132,"depth":234,"text":1133},{"id":1455,"depth":234,"text":1456},{"type":243,"title":9406,"description":9407},"Turn PLC Data Into Operational Visibility with FlowFuse","Reading and writing S7 data is just the start. FlowFuse extends your existing PLCs, SCADA, and MES, no rip-and-replace, into a single platform for remote device management, dashboards, and DevOps pipelines. Connect Siemens, Allen-Bradley, Modbus, and OPC UA devices, and get your first operational application running this week. SOC 2 certified, with RBAC, SSO, and self-hosted options. Talk to our team about your architecture.","2025-01-17","Learn how to read data from and write data to Siemens S7 PLCs (S7-1200\u002F1500) for industrial monitoring and control. This guide covers PLC setup, the S7 protocol over ISO-on-TCP, addressing, and building dashboards, no deep PLC expertise required.","\u002Fblog\u002F2025\u002F01\u002Fimages\u002Fs7-with-node-red.png","2026-06-03",{"keywords":9413,"excerpt":9414},"siemens s7 plc data, read data from s7 plc, write data to s7 plc, siemens s7 1200 with node-red, siemens s7 1500 with node-red, s7 with node-red, plc data integration, industrial automation",{"type":13,"value":9415},[9416],[16,9417,8200],{},"\u002Fblog\u002F2025\u002F01\u002Fintegrating-siemens-s7-plcs-with-node-red-guide",{"title":8193,"description":9409},{"loc":9418},"blog\u002F2025\u002F01\u002Fintegrating-siemens-s7-plcs-with-node-red-guide","A step-by-step beginner's guide to reading, writing, and monitoring data from Siemens S7-1200 and S7-1500 PLCs.",[7296,1518,263,9424],"how-to","This guide explains how to read data from and write data to Siemens S7 PLCs (S7-1200\u002F1500) using Node-RED and the S7 protocol over ISO-on-TCP (port 102). Prerequisites: enable PUT\u002FGET communication, disable optimized block access on your data blocks, and run Node-RED on a networked device (the FlowFuse Device Agent makes this remotely manageable). After installing an S7 node, you configure an endpoint with the PLC's IP, rack, and slot, map TIA Portal addresses to the node's address format, then use s7-in to read values and s7-out to write them, enabling remote monitoring, control, and dashboards without deep PLC expertise. The same patterns extend to Allen-Bradley, Modbus, and OPC UA devices for multi-vendor environments.","Zumw3mIy-PpnM75KupEm8sJVEiDdkOzuF4B2qYSxufk",1785528678987]